30 * @param parent QObject parent to pass forward |
30 * @param parent QObject parent to pass forward |
31 */ |
31 */ |
32 Model::Model(QObject *parent) : |
32 Model::Model(QObject *parent) : |
33 QAbstractListModel{parent} |
33 QAbstractListModel{parent} |
34 { |
34 { |
35 connect(this, &Model::dataChanged, [&](){ this->needRecache = true; }); |
|
36 } |
35 } |
37 |
36 |
38 /** |
37 /** |
39 * @returns the amount of elements in the model |
38 * @returns the amount of elements in the model |
40 */ |
39 */ |
130 const ldraw::Object* object = this->body[unsigned_cast(index)].get(); |
129 const ldraw::Object* object = this->body[unsigned_cast(index)].get(); |
131 return object->getProperty(property); |
130 return object->getProperty(property); |
132 } |
131 } |
133 |
132 |
134 /** |
133 /** |
135 * @brief Gets a list of GL polygons that are used to represent this model. |
|
136 * @details Will build polygons if polygons are outdated. |
|
137 * @param documents Documents to use to resolve subfile references |
|
138 * @return vector of GL polygons |
|
139 */ |
|
140 std::vector<gl::Polygon> Model::getPolygons(DocumentManager* documents) const |
|
141 { |
|
142 if (this->needRecache) |
|
143 { |
|
144 this->cachedPolygons.clear(); |
|
145 const std::optional<ModelId> modelId = documents->findIdForModel(this); |
|
146 if (modelId.has_value()) |
|
147 { |
|
148 ldraw::GetPolygonsContext context{modelId.value(), documents}; |
|
149 for (int i = 0; i < this->size(); i += 1) |
|
150 { |
|
151 this->getObjectPolygons(i, this->cachedPolygons, &context); |
|
152 } |
|
153 } |
|
154 this->needRecache = false; |
|
155 } |
|
156 return this->cachedPolygons; |
|
157 } |
|
158 |
|
159 /** |
|
160 * @brief Finds the position of the specified object in the model |
134 * @brief Finds the position of the specified object in the model |
161 * @param id Object id to look for |
135 * @param id Object id to look for |
162 * @return model index |
136 * @return model index |
163 */ |
137 */ |
164 QModelIndex Model::lookup(ldraw::id_t id) const |
138 QModelIndex Model::find(ldraw::id_t id) const |
165 { |
139 { |
166 // FIXME: This linear search will probably cause performance issues |
140 // FIXME: This linear search will probably cause performance issues |
167 for (std::size_t i = 0; i < this->body.size(); i += 1) |
141 for (std::size_t i = 0; i < this->body.size(); i += 1) |
168 { |
142 { |
169 if (this->body[i]->id == id) |
143 if (this->body[i]->id == id) |
209 } |
183 } |
210 } |
184 } |
211 #endif |
185 #endif |
212 |
186 |
213 /** |
187 /** |
214 * @brief Gets the GL polygons of the object at the specified position in the model |
|
215 * @param index Index of object in the model |
|
216 * @param polygons_out Vector to add polygons into |
|
217 * @param context Context to use to resolve subfile references |
|
218 */ |
|
219 void Model::getObjectPolygons( |
|
220 const int index, |
|
221 std::vector<gl::Polygon>& polygons_out, |
|
222 ldraw::GetPolygonsContext* context) const |
|
223 { |
|
224 const ldraw::Object* object = this->body[unsigned_cast(index)].get(); |
|
225 object->getPolygons(polygons_out, context); |
|
226 } |
|
227 |
|
228 /** |
|
229 * @brief Called by the editing context to signal to the model that editing is done. |
188 * @brief Called by the editing context to signal to the model that editing is done. |
230 */ |
189 */ |
231 void Model::editFinished() |
190 void Model::editFinished() |
232 { |
191 { |
233 this->editCounter -= 1; |
192 this->editCounter -= 1; |
237 * @brief Called by the editing context to indicate that the specified object has been modified. |
196 * @brief Called by the editing context to indicate that the specified object has been modified. |
238 * @param id ID of the object that has been modified |
197 * @param id ID of the object that has been modified |
239 */ |
198 */ |
240 void Model::objectModified(ldraw::id_t id) |
199 void Model::objectModified(ldraw::id_t id) |
241 { |
200 { |
242 const QModelIndex index = this->lookup(id); |
201 const QModelIndex index = this->find(id); |
243 Q_EMIT this->dataChanged(index, index); |
202 Q_EMIT this->dataChanged(index, index); |
244 } |
203 } |
245 |
204 |
246 /** |
205 /** |
247 * @brief Adds the given object into the model. |
206 * @brief Adds the given object into the model. |
248 * @param object r-value reference to the object |
207 * @param object r-value reference to the object |
249 */ |
208 */ |
250 void Model::append(ModelObjectPointer&& object) |
209 void Model::append(ModelObjectPointer&& object) |
251 { |
210 { |
252 const int position = static_cast<int>(this->body.size()); |
211 const int position = static_cast<int>(this->body.size()); |
253 Q_EMIT beginInsertRows({}, position, position); |
212 Q_EMIT this->beginInsertRows({}, position, position); |
254 this->body.push_back(std::move(object)); |
213 this->body.push_back(std::move(object)); |
255 Q_EMIT endInsertRows(); |
214 Q_EMIT this->endInsertRows(); |
256 this->needRecache = true; |
215 Q_EMIT this->objectAdded(position); |
257 } |
216 } |
258 |
217 |
259 /** |
218 /** |
260 * @brief Removes the object at the specified position |
219 * @brief Removes the object at the specified position |
261 * @param position |
220 * @param position |
262 */ |
221 */ |
263 void Model::remove(int position) |
222 void Model::remove(int position) |
264 { |
223 { |
265 if (position >= 0 and position < signed_cast(this->body.size())) |
224 if (position >= 0 and position < signed_cast(this->body.size())) |
266 { |
225 { |
267 Q_EMIT beginRemoveRows({}, position, position); |
226 Q_EMIT this->beginRemoveRows({}, position, position); |
|
227 const ldraw::id_t id = this->body[position]->id; |
268 this->body.erase(std::begin(this->body) + position); |
228 this->body.erase(std::begin(this->body) + position); |
269 Q_EMIT endRemoveRows(); |
229 Q_EMIT this->endRemoveRows(); |
270 this->needRecache = true; |
230 Q_EMIT this->objectRemoved(id); |
271 } |
231 } |
272 } |
232 } |
273 |
233 |
274 /** |
234 /** |
275 * @brief Gets the object pointer at the specified position |
235 * @brief Gets the object pointer at the specified position |
301 { |
261 { |
302 out << object.get()->toLDrawCode() << "\r\n"; |
262 out << object.get()->toLDrawCode() << "\r\n"; |
303 } |
263 } |
304 } |
264 } |
305 |
265 |
|
266 ldraw::Object* Model::operator[](int index) |
|
267 { |
|
268 if (index >= 0 and index < this->size()) |
|
269 { |
|
270 return this->body[index].get(); |
|
271 } |
|
272 else |
|
273 { |
|
274 throw std::out_of_range{"index out of range"}; |
|
275 } |
|
276 } |
|
277 |
306 /** |
278 /** |
307 * @brief Modifies the !LDRAW_ORG line so that it becomes unofficial |
279 * @brief Modifies the !LDRAW_ORG line so that it becomes unofficial |
308 */ |
280 */ |
309 void Model::makeUnofficial() |
281 void makeUnofficial(Model& model) |
310 { |
282 { |
311 if (this->body.size() >= 4) |
283 if (model.size() >= 4) |
312 { |
284 { |
313 const ldraw::id_t id = this->body[3]->id; |
285 const ldraw::Object* ldrawOrgLine = model[3]; |
314 if (this->isA<ldraw::MetaCommand>(id)) |
286 if (isA<ldraw::MetaCommand>(ldrawOrgLine)) |
315 { |
287 { |
316 const QString& body = this->body[3]->getProperty<ldraw::Property::Text>(); |
288 const QString& body = ldrawOrgLine->getProperty<ldraw::Property::Text>(); |
317 if (body.startsWith("!LDRAW_ORG ") and not body.startsWith("!LDRAW_ORG Unofficial_")) |
289 if (body.startsWith("!LDRAW_ORG ") and not body.startsWith("!LDRAW_ORG Unofficial_")) |
318 { |
290 { |
|
291 // Add Unofficial_ to part type |
319 QStringList tokens = body.split(" "); |
292 QStringList tokens = body.split(" "); |
320 tokens[1] = "Unofficial_" + tokens[1]; |
293 tokens[1] = "Unofficial_" + tokens[1]; |
321 // Remove the UPDATE tag |
294 // Remove the UPDATE tag if it's there |
322 if (tokens.size() >= 4 && tokens[2] == "UPDATE") |
295 if (tokens.size() >= 4 && tokens[2] == "UPDATE") |
323 { |
296 { |
324 tokens.removeAt(3); |
297 tokens.removeAt(3); |
325 tokens.removeAt(2); |
298 tokens.removeAt(2); |
326 } |
299 } |
327 EditContext editor = this->edit(); |
300 Model::EditContext editor = model.edit(); |
328 editor.setObjectProperty<ldraw::Property::Text>(id, tokens.join(" ")); |
301 editor.setObjectProperty<ldraw::Property::Text>(ldrawOrgLine->id, tokens.join(" ")); |
329 } |
302 } |
330 } |
303 } |
331 } |
304 } |
332 } |
305 } |