Xcos MVC: slight improvements in Adapters
[scilab.git] / scilab / modules / scicos / src / cpp / view_scilab / BlockAdapter.cpp
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 #include <string>
14 #include <vector>
15 #include <memory>
16
17 #include "internal.hxx"
18 #include "list.hxx"
19 #include "mlist.hxx"
20 #include "string.hxx"
21 #include "types.hxx"
22 #include "user.hxx"
23
24 #include "Controller.hxx"
25 #include "model/Block.hxx"
26 #include "BlockAdapter.hxx"
27 #include "DiagramAdapter.hxx"
28 #include "GraphicsAdapter.hxx"
29 #include "LinkAdapter.hxx"
30 #include "ModelAdapter.hxx"
31 #include "TextAdapter.hxx"
32
33 extern "C" {
34 #include "wchar.h"
35
36 #include "sci_malloc.h"
37 #include "charEncoding.h"
38 }
39
40 namespace org_scilab_modules_scicos
41 {
42 namespace view_scilab
43 {
44 namespace
45 {
46
47 struct graphics
48 {
49     static types::InternalType* get(const BlockAdapter& adaptor, const Controller& controller)
50     {
51         GraphicsAdapter localAdaptor = GraphicsAdapter(adaptor.getAdaptee());
52         return localAdaptor.getAsTList(new types::MList(), controller);
53     }
54
55     static bool set(BlockAdapter& adaptor, types::InternalType* v, Controller& controller)
56     {
57         GraphicsAdapter localAdaptor = GraphicsAdapter(adaptor.getAdaptee());
58         return localAdaptor.setAsTList(v, controller);
59     }
60 };
61
62 struct model
63 {
64     static types::InternalType* get(const BlockAdapter& adaptor, const Controller& controller)
65     {
66         ModelAdapter localAdaptor = ModelAdapter(adaptor.getAdaptee());
67         localAdaptor.setDiagram(adaptor.getDiagram());
68
69         return localAdaptor.getAsTList(new types::MList(), controller)->getAs<types::MList>();
70     }
71
72     static bool set(BlockAdapter& adaptor, types::InternalType* v, Controller& controller)
73     {
74         ModelAdapter localAdaptor = ModelAdapter(adaptor.getAdaptee());
75         if (!localAdaptor.setAsTList(v, controller))
76         {
77             return false;
78         }
79
80         adaptor.setDiagram(localAdaptor.getDiagram());
81
82         return true;
83     }
84 };
85
86 struct gui
87 {
88     static types::InternalType* get(const BlockAdapter& adaptor, const Controller& controller)
89     {
90         std::string Interface;
91         ScicosID adaptee = adaptor.getAdaptee()->id();
92         controller.getObjectProperty(adaptee, BLOCK, INTERFACE_FUNCTION, Interface);
93
94         return new types::String(Interface.data());
95     }
96
97     static bool set(BlockAdapter& adaptor, types::InternalType* v, Controller& controller)
98     {
99         if (v->getType() != types::InternalType::ScilabString)
100         {
101             return false;
102         }
103
104         types::String* current = v->getAs<types::String>();
105         if (current->getRows() != 1 || current->getCols() != 1)
106         {
107             return false;
108         }
109
110         wchar_t* w_name = current->get(0);
111         char* name = wide_string_to_UTF8(w_name);
112         std::string stName(name);
113         FREE(name);
114
115         ScicosID adaptee = adaptor.getAdaptee()->id();
116         controller.setObjectProperty(adaptee, BLOCK, INTERFACE_FUNCTION, stName);
117         return true;
118     }
119 };
120
121 struct doc
122 {
123     static types::InternalType* get(const BlockAdapter& adaptor, const Controller& /*controller*/)
124     {
125         return adaptor.getDocContent();
126     }
127
128     static bool set(BlockAdapter& adaptor, types::InternalType* v, Controller& /*controller*/)
129     {
130         adaptor.setDocContent(v->clone());
131         return true;
132     }
133 };
134
135 } /* namespace */
136
137 template<> property<BlockAdapter>::props_t property<BlockAdapter>::fields = property<BlockAdapter>::props_t();
138
139 BlockAdapter::BlockAdapter(std::shared_ptr<org_scilab_modules_scicos::model::Block> adaptee) :
140     BaseAdapter<BlockAdapter, org_scilab_modules_scicos::model::Block>(adaptee),
141     diagramAdapter(nullptr),
142     doc_content(new types::List())
143 {
144     if (property<BlockAdapter>::properties_have_not_been_set())
145     {
146         property<BlockAdapter>::fields.reserve(4);
147         property<BlockAdapter>::add_property(L"graphics", &graphics::get, &graphics::set);
148         property<BlockAdapter>::add_property(L"model", &model::get, &model::set);
149         property<BlockAdapter>::add_property(L"gui", &gui::get, &gui::set);
150         property<BlockAdapter>::add_property(L"doc", &doc::get, &doc::set);
151     }
152 }
153
154 BlockAdapter::BlockAdapter(const BlockAdapter& adapter) :
155     BaseAdapter<BlockAdapter, org_scilab_modules_scicos::model::Block>(adapter),
156     diagramAdapter(),
157     doc_content(adapter.getDocContent())
158 {
159     Controller controller;
160     std::vector<ScicosID> diagramChild;
161     controller.getObjectProperty(getAdaptee()->id(), BLOCK, CHILDREN, diagramChild);
162
163     if (!diagramChild.empty())
164     {
165         std::shared_ptr<org_scilab_modules_scicos::model::Diagram> diagram = std::static_pointer_cast<org_scilab_modules_scicos::model::Diagram>(controller.getObject(diagramChild[0]));
166         diagramAdapter = new DiagramAdapter(diagram);
167
168         // Extract the information of the old cloned diagram
169         DiagramAdapter* oldDiagram = adapter.getDiagram();
170         types::List* oldList_objects = oldDiagram->getListObjects()->getAs<types::List>();
171         std::vector<link_t> from_vec = oldDiagram->getFrom();
172         std::vector<link_t> to_vec = oldDiagram->getTo();
173
174         std::vector<ScicosID> diagramChildren;
175         controller.getObjectProperty(diagram->id(), DIAGRAM, CHILDREN, diagramChildren);
176
177         // FIXME: factor the following code with DiagramAdapter copy constructor?
178         std::vector<LinkAdapter*> linkListView; // Store the new LinkAdapters to make the linking at model-level after the loop
179         types::List* List_objects = new types::List();
180         for (int i = 0; i < static_cast<int>(diagramChildren.size()); ++i)
181         {
182             std::shared_ptr<org_scilab_modules_scicos::model::BaseObject> item = controller.getObject(diagramChildren[i]);
183             switch (item->kind())
184             {
185                 case ANNOTATION:
186                 {
187                     std::shared_ptr<org_scilab_modules_scicos::model::Annotation> annotation = std::static_pointer_cast<org_scilab_modules_scicos::model::Annotation>(item);
188                     TextAdapter* localAdaptor = new TextAdapter(annotation);
189
190                     List_objects->set(i, localAdaptor);
191                     continue;
192                 }
193                 case BLOCK:
194                 {
195                     std::shared_ptr<org_scilab_modules_scicos::model::Block> block = std::static_pointer_cast<org_scilab_modules_scicos::model::Block>(item);
196                     BlockAdapter* localAdaptor = new BlockAdapter(block);
197
198                     // If the diagram's block was a SuperBlock, make its new adapter point to its old diagram
199                     if (i < oldList_objects->getSize())
200                     {
201                         BlockAdapter* oldBlock = oldList_objects->get(i)->getAs<BlockAdapter>();
202                         DiagramAdapter* oldBlockDiagram = oldBlock->getDiagram();
203                         if (oldBlockDiagram != nullptr)
204                         {
205                             oldBlockDiagram->IncreaseRef();
206                         }
207                         localAdaptor->setDiagram(oldBlockDiagram);
208                     }
209
210                     List_objects->set(i, localAdaptor);
211                     continue;
212                 }
213                 case LINK:
214                 {
215                     std::shared_ptr<org_scilab_modules_scicos::model::Link> link = std::static_pointer_cast<org_scilab_modules_scicos::model::Link>(item);
216                     LinkAdapter* localAdaptor = new LinkAdapter(link);
217
218                     // Do the model linking in the next loop, in case the Link points to a Block that has not been added yet
219                     linkListView.push_back(localAdaptor);
220
221                     List_objects->set(i, localAdaptor);
222                     continue;
223                 }
224                 default:
225                 {
226                 }
227             }
228         }
229
230         // Do the linking at model-level, from the old 'from_vec' and 'to_vec'
231         for (int i = 0; i < static_cast<int>(linkListView.size()); ++i)
232         {
233             // Trigger 'from' and 'to' properties
234             linkListView[i]->setFromInModel(from_vec[i], controller);
235             linkListView[i]->setToInModel(to_vec[i], controller);
236         }
237
238         diagramAdapter->setListObjects(List_objects);
239         diagramAdapter->setFrom(from_vec);
240         diagramAdapter->setTo(to_vec);
241     }
242 }
243
244 BlockAdapter::~BlockAdapter()
245 {
246     if (diagramAdapter != nullptr)
247     {
248         // Update the model if the adaptee is being deleted
249         if (getAdaptee().use_count() == 3)
250         {
251             Controller controller;
252             controller.setObjectProperty(getAdaptee()->id(), BLOCK, CHILDREN, std::vector<ScicosID>());
253         }
254
255         diagramAdapter->DecreaseRef();
256         diagramAdapter->killMe();
257     }
258
259     doc_content->DecreaseRef();
260     doc_content->killMe();
261 }
262
263 std::wstring BlockAdapter::getTypeStr()
264 {
265     return getSharedTypeStr();
266 }
267
268 std::wstring BlockAdapter::getShortTypeStr()
269 {
270     return getSharedTypeStr();
271 }
272
273 DiagramAdapter* BlockAdapter::getDiagram() const
274 {
275     if (diagramAdapter != nullptr)
276     {
277         diagramAdapter->IncreaseRef();
278     }
279     return diagramAdapter;
280 }
281
282 void BlockAdapter::setDiagram(DiagramAdapter* v)
283 {
284     if (v != nullptr)
285     {
286         // The old 'diagramAdapter' needs to be freed after setting it to 'v'
287         DiagramAdapter* temp = diagramAdapter;
288
289         diagramAdapter = v;
290
291         if (temp != nullptr)
292         {
293             temp->DecreaseRef();
294             temp->killMe();
295         }
296     }
297 }
298
299 types::InternalType* BlockAdapter::getDocContent() const
300 {
301     doc_content->IncreaseRef();
302     return doc_content;
303 }
304
305 void BlockAdapter::setDocContent(types::InternalType* v)
306 {
307     doc_content->DecreaseRef();
308     doc_content->killMe();
309
310     v->IncreaseRef();
311     doc_content = v;
312 }
313
314 } /* namespace view_scilab */
315 } /* namespace org_scilab_modules_scicos */