7f8160297946d241f1427a46156c40cb395c5de6
[scilab.git] / scilab / modules / scicos / src / cpp / view_scilab / DiagramAdapter.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 <sstream>
16 #include <memory>
17
18 #include "internal.hxx"
19 #include "double.hxx"
20 #include "list.hxx"
21 #include "mlist.hxx"
22 #include "tlist.hxx"
23 #include "string.hxx"
24 #include "types.hxx"
25 #include "user.hxx"
26
27 #include "utilities.hxx"
28 #include "Controller.hxx"
29 #include "DiagramAdapter.hxx"
30 #include "Adapters.hxx"
31 #include "ParamsAdapter.hxx"
32 #include "BlockAdapter.hxx"
33 #include "LinkAdapter.hxx"
34 #include "TextAdapter.hxx"
35 #include "model/BaseObject.hxx"
36
37 extern "C" {
38 #include "sci_malloc.h"
39 #include "charEncoding.h"
40 }
41
42 namespace org_scilab_modules_scicos
43 {
44 namespace view_scilab
45 {
46 namespace
47 {
48
49 const std::wstring TextSharedTypeStr (L"Text");
50
51 struct props
52 {
53
54     static types::InternalType* get(const DiagramAdapter& adaptor, const Controller& controller)
55     {
56         ParamsAdapter localAdaptor = ParamsAdapter(adaptor.getAdaptee());
57         return localAdaptor.getAsTList(new types::TList(), controller);
58     }
59
60     static bool set(DiagramAdapter& adaptor, types::InternalType* v, Controller& controller)
61     {
62         ParamsAdapter localAdaptor = ParamsAdapter(adaptor.getAdaptee());
63         return localAdaptor.setAsTList(v, controller);
64     }
65 };
66
67 struct objs
68 {
69
70     static types::InternalType* get(const DiagramAdapter& adaptor, const Controller& controller)
71     {
72         model::Diagram* adaptee = adaptor.getAdaptee().get();
73
74         std::vector<ScicosID> children;
75         controller.getObjectProperty(adaptee->id(), DIAGRAM, CHILDREN, children);
76
77         types::List* o = new types::List();
78
79         std::vector<link_t> from = adaptor.getFrom();
80         std::vector<link_t> to = adaptor.getTo();
81
82         int link_number = 0;
83         Controller newController = Controller();
84         for (int i = 0; i < static_cast<int>(children.size()); ++i)
85         {
86             std::shared_ptr<model::BaseObject> item = newController.getObject(children[i]);
87             switch (item->kind())
88             {
89                 case ANNOTATION:
90                 {
91                     std::shared_ptr<model::Annotation> annotation = std::static_pointer_cast<model::Annotation>(item);
92                     TextAdapter* localAdaptor = new TextAdapter(annotation);
93                     o->set(i, localAdaptor);
94                     continue;
95                 }
96                 case BLOCK:
97                 {
98                     std::shared_ptr<model::Block> block = std::static_pointer_cast<model::Block>(item);
99                     BlockAdapter* localAdaptor = new BlockAdapter(block);
100
101                     types::List* list_objects = adaptor.getListObjects()->getAs<types::List>();
102                     if (i < list_objects->getSize())
103                     {
104                         BlockAdapter* oldBlock = list_objects->get(i)->getAs<BlockAdapter>();
105                         DiagramAdapter* oldBlockDiagram = oldBlock->getDiagram();
106                         if (oldBlockDiagram != nullptr)
107                         {
108                             oldBlockDiagram->IncreaseRef();
109                         }
110                         localAdaptor->setDiagram(oldBlockDiagram);
111                     }
112
113                     o->set(i, localAdaptor);
114                     continue;
115                 }
116                 case LINK:
117                 {
118                     std::shared_ptr<model::Link> link = std::static_pointer_cast<model::Link>(item);
119                     LinkAdapter* localAdaptor = new LinkAdapter(link);
120
121                     // In case a Link points to a Block that has not been added yet,
122                     // retrieve the 'from' and 'to' values from the Diagram Adapter if they have been saved
123                     if (link_number < static_cast<int>(from.size()))
124                     {
125                         localAdaptor->setFrom(from[link_number]);
126                         localAdaptor->setTo(to[link_number]);
127                         link_number++;
128                     }
129                     o->set(i, localAdaptor);
130                     continue;
131                 }
132                 default:
133                     return 0;
134             }
135         }
136         return o;
137     }
138
139     static bool set(DiagramAdapter& adaptor, types::InternalType* v, Controller& controller)
140     {
141         // Decode the list and set all children of the Diagram
142         if (v->getType() != types::InternalType::ScilabList)
143         {
144             return false;
145         }
146
147         model::Diagram* adaptee = adaptor.getAdaptee().get();
148
149         types::List* list = v->getAs<types::List>();
150
151         // Clear the children list before the loop to reset the diagram children
152         // and clear the old Links information
153         std::vector<ScicosID> diagramChildren;
154         controller.getObjectProperty(adaptee->id(), DIAGRAM, CHILDREN, diagramChildren);
155         for (ScicosID id : diagramChildren)
156         {
157             auto o = controller.getObject(id);
158             controller.setObjectProperty(id, o->kind(), PARENT_DIAGRAM, 0ll);
159         }
160         diagramChildren.clear();
161
162         // Set the children to the right IDs
163         std::vector<LinkAdapter*> linkListView;
164         for (int i = 0; i < list->getSize(); ++i)
165         {
166             if (list->get(i)->getType() == types::InternalType::ScilabUserType)
167             {
168
169                 const Adapters::adapters_index_t adapter_index = Adapters::instance().lookup_by_typename(list->get(i)->getShortTypeStr());
170
171                 // Then, each adapter gets linked to the diagram through its adaptee (PARENT_DIAGRAM)
172                 // and the diagram's adaptee lists its adaptees (CHILDREN).
173                 ScicosID id;
174                 switch (adapter_index)
175                 {
176                     case Adapters::BLOCK_ADAPTER:
177                     {
178                         BlockAdapter* modelElement = list->get(i)->getAs<BlockAdapter>();
179
180                         id = modelElement->getAdaptee()->id();
181
182                         controller.setObjectProperty(id, BLOCK, PARENT_DIAGRAM, adaptee->id());
183                         diagramChildren.push_back(id);
184                         break;
185                     }
186                     case Adapters::LINK_ADAPTER:
187                     {
188                         LinkAdapter* modelElement = list->get(i)->getAs<LinkAdapter>();
189
190                         id = modelElement->getAdaptee()->id();
191
192                         controller.setObjectProperty(id, LINK, PARENT_DIAGRAM, adaptee->id());
193
194                         // Do the linking in the next loop, in case the Link points to a Block that has not been added yet
195                         linkListView.push_back(modelElement);
196
197                         diagramChildren.push_back(id);
198                         break;
199                     }
200                     case Adapters::TEXT_ADAPTER:
201                     {
202                         TextAdapter* modelElement = list->get(i)->getAs<TextAdapter>();
203
204                         id = modelElement->getAdaptee()->id();
205
206                         controller.setObjectProperty(id, ANNOTATION, PARENT_DIAGRAM, adaptee->id());
207                         diagramChildren.push_back(id);
208                         break;
209                     }
210                     default:
211                         return false;
212                 }
213             }
214             else if (list->get(i)->getType() == types::InternalType::ScilabMList)
215             {
216                 // Allow to pass mlists to 'objs', representing Text blocks
217                 types::MList* modelElement = list->get(i)->getAs<types::MList>();
218                 types::String* header = modelElement->getFieldNames();
219                 if (header->get(0) != TextSharedTypeStr)
220                 {
221                     return false;
222                 }
223
224                 // Create a Text block based on the input MList and add it to the diagram
225                 ScicosID newID = controller.createObject(ANNOTATION);
226                 TextAdapter* newAdaptor = new TextAdapter(std::static_pointer_cast<model::Annotation>(controller.getObject(newID)));
227                 // Fill the block with the input mlist
228                 if (!newAdaptor->setAsTList(modelElement, controller))
229                 {
230                     return false;
231                 }
232
233                 // Modify the input list to save the new block
234                 list->set(i, newAdaptor);
235
236                 controller.setObjectProperty(newID, ANNOTATION, PARENT_DIAGRAM, adaptee->id());
237                 diagramChildren.push_back(newID);
238             }
239             else
240             {
241                 return false;
242             }
243         }
244         controller.setObjectProperty(adaptee->id(), DIAGRAM, CHILDREN, diagramChildren);
245
246         adaptor.setListObjects(v);
247
248         std::vector<link_t> from_content (linkListView.size());
249         std::vector<link_t> to_content (linkListView.size());
250         // Do the linking at model-level
251         for (int i = 0; i < static_cast<int>(linkListView.size()); ++i)
252         {
253             // Trigger 'from' and 'to' properties
254             from_content[i] = linkListView[i]->getFrom();
255             if (!linkListView[i]->setFromInModel(from_content[i], controller) && (from_content[i].block != 0 && from_content[i].port != 0))
256             {
257                 return false;
258             }
259             to_content[i] = linkListView[i]->getTo();
260             if (!linkListView[i]->setToInModel(to_content[i], controller) && (to_content[i].block != 0 && to_content[i].port != 0))
261             {
262                 return false;
263             }
264         }
265         adaptor.setFrom(from_content);
266         adaptor.setTo(to_content);
267
268         return true;
269     }
270 };
271
272 struct version
273 {
274
275     static types::InternalType* get(const DiagramAdapter& adaptor, const Controller& controller)
276     {
277         model::Diagram* adaptee = adaptor.getAdaptee().get();
278
279         std::string version;
280         controller.getObjectProperty(adaptee->id(), DIAGRAM, VERSION_NUMBER, version);
281
282         return new types::String(version.data());
283     }
284
285     static bool set(DiagramAdapter& adaptor, types::InternalType* v, Controller& controller)
286     {
287         if (v->getType() == types::InternalType::ScilabString)
288         {
289             types::String* current = v->getAs<types::String>();
290             if (current->getSize() != 1)
291             {
292                 return false;
293             }
294
295             model::Diagram* adaptee = adaptor.getAdaptee().get();
296
297             char* c_str = wide_string_to_UTF8(current->get(0));
298             std::string version (c_str);
299             FREE(c_str);
300
301             controller.setObjectProperty(adaptee->id(), DIAGRAM, VERSION_NUMBER, version);
302             return true;
303         }
304         else if (v->getType() == types::InternalType::ScilabDouble)
305         {
306             types::Double* current = v->getAs<types::Double>();
307             if (current->getSize() != 0)
308             {
309                 return false;
310             }
311
312             model::Diagram* adaptee = adaptor.getAdaptee().get();
313
314             std::string version;
315             controller.setObjectProperty(adaptee->id(), DIAGRAM, VERSION_NUMBER, version);
316             return true;
317         }
318
319         return false;
320     }
321 };
322
323 struct contrib
324 {
325
326     static types::InternalType* get(const DiagramAdapter& adaptor, const Controller& /*controller*/)
327     {
328         return adaptor.getContribContent();
329     }
330
331     static bool set(DiagramAdapter& adaptor, types::InternalType* v, Controller& /*controller*/)
332     {
333         adaptor.setContribContent(v->clone());
334         return true;
335     }
336 };
337
338 } /* namespace */
339
340 template<> property<DiagramAdapter>::props_t property<DiagramAdapter>::fields = property<DiagramAdapter>::props_t();
341
342 DiagramAdapter::DiagramAdapter(std::shared_ptr<org_scilab_modules_scicos::model::Diagram> adaptee) :
343     BaseAdapter<DiagramAdapter, org_scilab_modules_scicos::model::Diagram>(adaptee),
344     list_objects(new types::List()),
345     from_vec(),
346     to_vec(),
347     contrib_content(new types::List())
348 {
349     if (property<DiagramAdapter>::properties_have_not_been_set())
350     {
351         property<DiagramAdapter>::fields.reserve(4);
352         property<DiagramAdapter>::add_property(L"props", &props::get, &props::set);
353         property<DiagramAdapter>::add_property(L"objs", &objs::get, &objs::set);
354         property<DiagramAdapter>::add_property(L"version", &version::get, &version::set);
355         property<DiagramAdapter>::add_property(L"contrib", &contrib::get, &contrib::set);
356     }
357 }
358
359 DiagramAdapter::DiagramAdapter(const DiagramAdapter& adapter) :
360     BaseAdapter<DiagramAdapter, org_scilab_modules_scicos::model::Diagram>(adapter),
361     list_objects(),
362     from_vec(adapter.from_vec),
363     to_vec(adapter.to_vec),
364     contrib_content(adapter.getContribContent())
365 {
366     // Generate an Adapter for each child of the cloned Diagram and store them all in 'list_objects'
367     Controller controller;
368     std::vector<ScicosID> children;
369     controller.getObjectProperty(getAdaptee()->id(), DIAGRAM, CHILDREN, children);
370
371     std::vector<LinkAdapter*> linkListView; // Store the new LinkAdapters to make the linking at model-level after the loop
372     types::List* List_objects = new types::List();
373     for (int i = 0; i < static_cast<int>(children.size()); ++i)
374     {
375         std::shared_ptr<model::BaseObject> item = controller.getObject(children[i]);
376         switch (item->kind())
377         {
378             case ANNOTATION:
379             {
380                 std::shared_ptr<model::Annotation> annotation = std::static_pointer_cast<model::Annotation>(item);
381                 TextAdapter* localAdaptor = new TextAdapter(annotation);
382
383                 List_objects->set(i, localAdaptor);
384                 continue;
385             }
386             case BLOCK:
387             {
388                 std::shared_ptr<model::Block> block = std::static_pointer_cast<model::Block>(item);
389                 BlockAdapter* localAdaptor = new BlockAdapter(block);
390
391                 // If the diagram's block was a SuperBlock, make its new adapter point to its old diagram
392                 types::List* oldList_objects = adapter.getListObjects()->getAs<types::List>();
393                 if (i < oldList_objects->getSize())
394                 {
395                     BlockAdapter* oldBlock = oldList_objects->get(i)->getAs<BlockAdapter>();
396                     DiagramAdapter* oldBlockDiagram = oldBlock->getDiagram();
397                     if (oldBlockDiagram != nullptr)
398                     {
399                         oldBlockDiagram->IncreaseRef();
400                     }
401                     localAdaptor->setDiagram(oldBlockDiagram);
402                 }
403
404                 List_objects->set(i, localAdaptor);
405                 continue;
406             }
407             case LINK:
408             {
409                 std::shared_ptr<model::Link> link = std::static_pointer_cast<model::Link>(item);
410                 LinkAdapter* localAdaptor = new LinkAdapter(link);
411
412                 // Do the model linking in the next loop, in case the Link points to a Block that has not been added yet
413                 linkListView.push_back(localAdaptor);
414
415                 List_objects->set(i, localAdaptor);
416                 continue;
417             }
418             default:
419             {
420             }
421         }
422     }
423
424     // Do the linking at model-level, from the old 'from_vec' and 'to_vec'
425     for (int i = 0; i < static_cast<int>(linkListView.size()); ++i)
426     {
427         // Trigger 'from' and 'to' properties
428         linkListView[i]->setFromInModel(from_vec[i], controller);
429         linkListView[i]->setToInModel(to_vec[i], controller);
430     }
431
432     list_objects = List_objects;
433 }
434
435 DiagramAdapter::~DiagramAdapter()
436 {
437     // Unlink the diagram's children if necessary
438     Controller controller;
439     std::vector<ScicosID> diagramChildren;
440     if (getAdaptee() != 0)
441     {
442         controller.getObjectProperty(getAdaptee()->id(), DIAGRAM, CHILDREN, diagramChildren);
443         for (ScicosID id : diagramChildren)
444         {
445             auto o = controller.getObject(id);
446             controller.setObjectProperty(id, o->kind(), PARENT_DIAGRAM, 0ll);
447         }
448         diagramChildren.clear();
449         controller.setObjectProperty(getAdaptee()->id(), DIAGRAM, CHILDREN, diagramChildren);
450     }
451
452     list_objects->DecreaseRef();
453     list_objects->killMe();
454
455     contrib_content->DecreaseRef();
456     contrib_content->killMe();
457 }
458
459 std::wstring DiagramAdapter::getTypeStr()
460 {
461     return getSharedTypeStr();
462 }
463 std::wstring DiagramAdapter::getShortTypeStr()
464 {
465     return getSharedTypeStr();
466 }
467
468 types::InternalType* DiagramAdapter::getContribContent() const
469 {
470     contrib_content->IncreaseRef();
471     return contrib_content;
472 }
473
474 void DiagramAdapter::setContribContent(types::InternalType* v)
475 {
476     contrib_content->DecreaseRef();
477     contrib_content->killMe();
478
479     v->IncreaseRef();
480     contrib_content = v;
481 }
482
483 types::InternalType* DiagramAdapter::getListObjects() const
484 {
485     return list_objects;
486 }
487
488 void DiagramAdapter::setListObjects(types::InternalType* v)
489 {
490     // The old 'list_objects' needs to be freed after setting it to 'v'
491     types::InternalType* temp = list_objects;
492
493     v->IncreaseRef();
494     list_objects = v;
495
496     temp->DecreaseRef();
497     temp->killMe();
498 }
499
500 std::vector<link_t> DiagramAdapter::getFrom() const
501 {
502     return from_vec;
503 }
504
505 void DiagramAdapter::setFrom(const std::vector<link_t>& from)
506 {
507     from_vec = from;
508 }
509
510 std::vector<link_t> DiagramAdapter::getTo() const
511 {
512     return to_vec;
513 }
514
515 void DiagramAdapter::setTo(const std::vector<link_t>& to)
516 {
517     to_vec = to;
518 }
519
520 } /* namespace view_scilab */
521 } /* namespace org_scilab_modules_scicos */