Xcos MVC: implement clone / delete on the Model side
[scilab.git] / scilab / modules / scicos / src / cpp / Model.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 <utility>
15 #include <algorithm>
16
17 #include "Model.hxx"
18 #include "utilities.hxx"
19
20 #include "model/BaseObject.hxx"
21 #include "model/Annotation.hxx"
22 #include "model/Diagram.hxx"
23 #include "model/Block.hxx"
24 #include "model/Link.hxx"
25 #include "model/Port.hxx"
26
27 namespace org_scilab_modules_scicos
28 {
29
30 Model::Model() :
31     lastId(0), allObjects()
32 {
33     std::vector<int> datatypeDefault (3, 1);
34     datatypeDefault[0] = -1;
35     datatypes.push_back(new model::Datatype(datatypeDefault));
36 }
37
38 Model::~Model()
39 {
40     while (!datatypes.empty())
41     {
42         Model::erase(datatypes[0]);
43     }
44     datatypes.clear();
45 }
46
47 ScicosID Model::createObject(kind_t k)
48 {
49     /*
50      * Allocate the object per kind
51      */
52     model::BaseObject* o;
53     switch (k)
54     {
55         case ANNOTATION:
56             o = new model::Annotation();
57             break;
58         case DIAGRAM:
59             o = new model::Diagram();
60             break;
61         case BLOCK:
62             o = new model::Block();
63             break;
64         case LINK:
65             o = new model::Link();
66             break;
67         case PORT:
68             o = new model::Port();
69             break;
70     }
71
72     /*
73      * Found the next unused id
74      */
75     lastId++;
76     if (lastId == 0)
77     {
78         lastId++;
79     }
80
81     // full map, detection
82     bool has_looped = false;
83
84     objects_map_t::iterator iter = allObjects.lower_bound(lastId);
85     while (iter != allObjects.end() && !(lastId < iter->first)) // while key is found
86     {
87         // try a valid ID
88         lastId++;
89         if (lastId == 0)
90         {
91             lastId++;
92
93             // if the map is full, return 0;
94             if (has_looped)
95             {
96                 delete o;
97                 return 0;
98             }
99             has_looped = true;
100         }
101
102         // look for it
103         iter = allObjects.lower_bound(lastId);
104     }
105
106     /*
107      * Insert then return
108      */
109     allObjects.insert(iter, std::make_pair(lastId, o));
110     o->id(lastId);
111     return lastId;
112 }
113
114 void Model::deleteObject(ScicosID uid)
115 {
116     objects_map_t::iterator iter = allObjects.lower_bound(uid);
117     if (iter == allObjects.end() || uid < iter->first)
118     {
119         throw std::string("key has not been found");
120     }
121
122     delete iter->second;
123     allObjects.erase(iter);
124 }
125
126 model::BaseObject* Model::getObject(ScicosID uid) const
127 {
128     objects_map_t::const_iterator iter = allObjects.lower_bound(uid);
129     if (iter == allObjects.end() || uid < iter->first)
130     {
131         throw std::string("key has not been found");
132     }
133
134     return iter->second;
135 }
136
137 update_status_t Model::setObject(model::BaseObject* o)
138 {
139     objects_map_t::iterator iter = allObjects.lower_bound(o->id());
140     if (iter == allObjects.end() || o->id() < iter->first)
141     {
142         throw std::string("key has not been found");
143     }
144
145     if (*iter->second == *o)
146     {
147         return NO_CHANGES;
148     }
149
150     o->id(iter->second->id());
151     delete iter->second;
152     iter->second = o;
153     return SUCCESS;
154 }
155
156 // datatypes being a vector of Datatype pointers, we need a dereferencing comparison operator to use std::lower_bound()
157 static bool isInferior(const model::Datatype* d1, const model::Datatype* d2)
158 {
159     return *d1 < *d2;
160 }
161
162 model::Datatype* Model::flyweight(const model::Datatype& d)
163 {
164     datatypes_set_t::iterator iter = std::lower_bound(datatypes.begin(), datatypes.end(), &d, isInferior);
165     if (iter != datatypes.end() && !(d < **iter)) // if d is found
166     {
167         (*iter)->refCount++;
168         return *iter;
169     }
170     else
171     {
172         return *datatypes.insert(iter, new model::Datatype(d));
173     }
174 }
175
176 void Model::erase(model::Datatype* d)
177 {
178     datatypes_set_t::iterator iter = std::lower_bound(datatypes.begin(), datatypes.end(), d, isInferior);
179     if (iter != datatypes.end() && !(*d < **iter)) // if d is found
180     {
181         (*iter)->refCount--;
182         if ((*iter)->refCount < 0)
183         {
184             delete *iter;
185             datatypes.erase(iter);
186         }
187     }
188 }
189
190 } /* namespace org_scilab_modules_scicos */