Wed, 08 Jun 2022 23:02:04 +0300
well that's embarrassing
24 | 1 | /* |
2 | * LDForge: LDraw parts authoring CAD | |
3 | * Copyright (C) 2013 - 2020 Teemu Piippo | |
4 | * | |
5 | * This program is free software: you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation, either version 3 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
17 | */ | |
18 | ||
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
19 | #include <QFile> |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
20 | #include <QDir> |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
21 | #include <QFileInfo> |
148 | 22 | #include <QSaveFile> |
3 | 23 | #include "documentmanager.h" |
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
24 | #include "parser.h" |
3 | 25 | |
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
26 | /** |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
27 | * @brief Constructs a new document manager |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
28 | * @param parent Parent object |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
29 | */ |
5 | 30 | DocumentManager::DocumentManager(QObject* parent) : |
31 | QObject{parent} | |
32 | { | |
33 | } | |
34 | ||
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
35 | /** |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
36 | * @brief Creates a new model. |
148 | 37 | * @returns the ID of the new model |
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
38 | */ |
148 | 39 | ModelId DocumentManager::newModel() |
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
40 | { |
148 | 41 | const ModelId modelId{++this->modelIdCounter}; |
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
42 | const QString name = makeNewModelName(); |
148 | 43 | this->openModels[modelId] = ModelInfo{ |
200 | 44 | .model = std::make_unique<Model>(this), |
150
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
45 | .id = modelId, |
148 | 46 | .opentype = OpenType::ManuallyOpened, |
47 | }; | |
150
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
48 | this->makePolygonCacheForModel(modelId); |
148 | 49 | return modelId; |
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
50 | } |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
51 | |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
52 | /** |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
53 | * @brief Looks for a model by name |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
54 | * @param name Name of the model |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
55 | * @returns model or null |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
56 | */ |
148 | 57 | Model* DocumentManager::findDependencyByName(const ModelId modelId, const QString& name) |
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
58 | { |
148 | 59 | const auto modelsIterator = this->openModels.find(modelId); |
60 | if (modelsIterator != std::end(this->openModels)) | |
61 | { | |
62 | const auto& dependencies = modelsIterator->second.dependencies; | |
63 | const auto dependenciesIterator = dependencies.find(name); | |
64 | if (dependenciesIterator != dependencies.end()) | |
65 | { | |
66 | ModelInfo& modelInfo = this->openModels[dependenciesIterator->second]; | |
67 | return modelInfo.model.get(); | |
68 | } | |
69 | else | |
70 | { | |
71 | return nullptr; | |
72 | } | |
73 | } | |
74 | else | |
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
75 | { |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
76 | return nullptr; |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
77 | } |
148 | 78 | } |
79 | ||
80 | /** | |
81 | * @brief Gets a model pointer by id or nullptr if not found | |
82 | * @param modelId id of model to find | |
83 | * @returns model pointer or null | |
84 | */ | |
85 | Model *DocumentManager::getModelById(ModelId modelId) | |
86 | { | |
87 | const auto iterator = this->openModels.find(modelId); | |
88 | if (iterator != this->openModels.end()) | |
89 | { | |
90 | return iterator->second.model.get(); | |
91 | } | |
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
92 | else |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
93 | { |
148 | 94 | return nullptr; |
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
95 | } |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
96 | } |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
97 | |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
98 | QString pathToName(const QFileInfo& path) |
3 | 99 | { |
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
100 | static const char* paths[] = { |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
101 | "s", |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
102 | "48" |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
103 | "8" |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
104 | }; |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
105 | const QString baseName = path.fileName(); |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
106 | const QString dirName = QFileInfo{path.dir().path()}.fileName(); |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
107 | QString result; |
17 | 108 | if (std::find(std::begin(paths), std::end(paths), dirName) != std::end(paths)) |
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
109 | { |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
110 | result = dirName + "\\" + baseName; |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
111 | } |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
112 | else |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
113 | { |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
114 | result = baseName; |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
115 | } |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
116 | return result; |
3 | 117 | } |
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
118 | |
147 | 119 | /** |
120 | * @brief Tries to open the model at the specified path | |
121 | * @param path Path to the model to open | |
122 | * @param errorStream Where to write any errors | |
123 | * @param openType rationale behind opening this file | |
148 | 124 | * @returns model id, or no value on error |
147 | 125 | */ |
148 | 126 | std::optional<ModelId> DocumentManager::openModel( |
127 | const QString& path, | |
128 | QTextStream& errorStream, | |
129 | const OpenType openType | |
130 | ) { | |
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
131 | QFile file{path}; |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
132 | const QString name = pathToName(path); |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
133 | file.open(QFile::ReadOnly | QFile::Text); |
148 | 134 | std::unique_ptr<Model> newModel = std::make_unique<Model>(this); |
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
135 | QTextStream textStream{&file}; |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
136 | Parser parser{file}; |
152 | 137 | parser.parseBody(*newModel); |
148 | 138 | std::optional<ModelId> result; |
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
139 | if (file.error() == QFile::NoError) |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
140 | { |
148 | 141 | const ModelId modelId{++this->modelIdCounter}; |
150
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
142 | this->openModels[modelId] = {std::move(newModel), modelId, path, openType}; |
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
143 | this->makePolygonCacheForModel(modelId); |
148 | 144 | result = modelId; |
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
145 | } |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
146 | else |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
147 | { |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
148 | errorStream << file.errorString(); |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
149 | } |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
150 | return result; |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
151 | } |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
152 | |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
153 | QString DocumentManager::makeNewModelName() |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
154 | { |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
155 | untitledNameCounter += 1; |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
156 | return "untitled-" + QString::number(untitledNameCounter); |
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
157 | } |
12 | 158 | |
148 | 159 | void DocumentManager::loadDependenciesForAllModels(const LibraryManager& libraries, QTextStream& errorStream) |
160 | { | |
161 | for (const auto& modelInfoPair : this->openModels) | |
162 | { | |
163 | this->loadDependenciesForModel(modelInfoPair.first, modelInfoPair.second.path, libraries, errorStream); | |
164 | } | |
165 | } | |
166 | ||
167 | struct DocumentManager::LoadDepedenciesBag | |
168 | { | |
169 | const LibraryManager& libraries; | |
170 | QStringList missing; | |
171 | QSet<ModelId> processed; | |
172 | QTextStream& errorStream; | |
173 | }; | |
174 | ||
12 | 175 | void DocumentManager::loadDependenciesForModel( |
148 | 176 | const ModelId modelId, |
23
3387a84ddaba
fixed a pile of nonsense that caused subfiles to go haywire
Teemu Piippo <teemu@hecknology.net>
parents:
17
diff
changeset
|
177 | const QString& path, |
12 | 178 | const LibraryManager& libraries, |
179 | QTextStream& errorStream) | |
180 | { | |
148 | 181 | LoadDepedenciesBag bag { |
182 | .libraries = libraries, | |
183 | .missing = {}, | |
184 | .processed = {}, | |
185 | .errorStream = errorStream, | |
186 | }; | |
187 | this->loadDependenciesForModel(modelId, path, bag); | |
188 | if (not bag.missing.empty()) | |
12 | 189 | { |
148 | 190 | bag.missing.sort(Qt::CaseInsensitive); |
206
654661eab7f3
More refactor, merged main.h, basics.h and utility.h into one header file basics.h and removed plenty of unused code
Teemu Piippo <teemu@hecknology.net>
parents:
201
diff
changeset
|
191 | errorStream << tr("The following files could not be opened: %1") |
654661eab7f3
More refactor, merged main.h, basics.h and utility.h into one header file basics.h and removed plenty of unused code
Teemu Piippo <teemu@hecknology.net>
parents:
201
diff
changeset
|
192 | .arg(bag.missing.join(", ")); |
148 | 193 | } |
194 | } | |
195 | ||
196 | void DocumentManager::closeDocument(const ModelId modelId) | |
197 | { | |
198 | ModelInfo* modelInfo = findInMap(this->openModels, modelId); | |
199 | if (modelInfo != nullptr) | |
200 | { | |
201 | modelInfo->opentype = OpenType::AutomaticallyOpened; | |
202 | this->prune(); | |
203 | } | |
204 | } | |
205 | ||
206 | const QString *DocumentManager::modelPath(ModelId modelId) const | |
207 | { | |
208 | const auto iterator = this->openModels.find(modelId); | |
209 | if (iterator != this->openModels.end()) | |
210 | { | |
211 | return &iterator->second.path; | |
212 | } | |
213 | else | |
214 | { | |
215 | return nullptr; | |
216 | } | |
217 | } | |
218 | ||
219 | /** | |
220 | * @brief Changes the path of the specified model. Since the name of the file may change, | |
221 | * changing the path can cause dependencies to be resolved differently. As such, dependencies | |
222 | * need to be resolved for all files after this operation. | |
223 | * @param modelId Model to change the path of | |
224 | * @param newPath New path | |
225 | * @param libraries Library manager for the purpose of dependency resolving | |
226 | * @param errorStream Where to write any errors regarding dependency resolving | |
227 | */ | |
228 | void DocumentManager::setModelPath( | |
229 | const ModelId modelId, | |
230 | const QString &newPath, | |
231 | const LibraryManager &libraries, | |
232 | QTextStream &errorStream) | |
233 | { | |
234 | auto modelInfoPair = this->openModels.find(modelId); | |
235 | if (true | |
236 | and modelInfoPair != this->openModels.end() | |
237 | and modelInfoPair->second.opentype == OpenType::ManuallyOpened | |
238 | ) { | |
239 | modelInfoPair->second.path = newPath; | |
240 | this->loadDependenciesForAllModels(libraries, errorStream); | |
12 | 241 | } |
242 | } | |
243 | ||
148 | 244 | bool DocumentManager::saveModel(const ModelId modelId, QTextStream &errors) |
147 | 245 | { |
148 | 246 | const QString* const path = this->modelPath(modelId); |
247 | if (path != nullptr) | |
147 | 248 | { |
148 | 249 | QSaveFile file{*path}; |
250 | file.setDirectWriteFallback(true); | |
251 | if (file.open(QSaveFile::WriteOnly)) | |
147 | 252 | { |
148 | 253 | // if path is not nullptr, getModelById will always return a value as well |
151 | 254 | ::save(*this->getModelById(modelId), &file); |
148 | 255 | const bool commitSucceeded = file.commit(); |
256 | if (not commitSucceeded) | |
257 | { | |
258 | errors << tr("Could not save: %1").arg(file.errorString()); | |
259 | return false; | |
260 | } | |
261 | else | |
262 | { | |
263 | return true; | |
264 | } | |
265 | } | |
266 | else | |
267 | { | |
268 | errors << tr("Could not open %1 for writing: %2") | |
206
654661eab7f3
More refactor, merged main.h, basics.h and utility.h into one header file basics.h and removed plenty of unused code
Teemu Piippo <teemu@hecknology.net>
parents:
201
diff
changeset
|
269 | .arg(file.fileName(), file.errorString()); |
148 | 270 | return false; |
147 | 271 | } |
272 | } | |
148 | 273 | else |
274 | { | |
275 | errors << tr("Bad model ID %1").arg(modelId.value); | |
276 | return false; | |
277 | } | |
147 | 278 | } |
279 | ||
148 | 280 | /** |
281 | * @brief Searches the open models for the specified model and returns its id if found | |
282 | * @param model model to look for | |
283 | * @return id or no value if not found | |
284 | */ | |
285 | std::optional<ModelId> DocumentManager::findIdForModel(const Model *model) const | |
147 | 286 | { |
148 | 287 | std::optional<ModelId> result; |
288 | for (auto it = this->openModels.begin(); it != this->openModels.end(); ++it) | |
147 | 289 | { |
148 | 290 | if (it->second.model.get() == model) |
147 | 291 | { |
148 | 292 | result = it->first; |
293 | break; | |
294 | } | |
295 | } | |
296 | return result; | |
297 | } | |
298 | ||
150
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
299 | PolygonCache *DocumentManager::getPolygonCacheForModel(ModelId modelId) |
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
300 | { |
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
301 | auto it = this->polygonCaches.find(modelId); |
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
302 | if (it != this->polygonCaches.end()) |
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
303 | { |
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
304 | return &it->second; |
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
305 | } |
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
306 | else |
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
307 | { |
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
308 | return nullptr; |
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
309 | } |
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
310 | } |
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
311 | |
148 | 312 | /** |
313 | * @brief Cleans up and erases models that are no longer required. | |
314 | */ | |
315 | void DocumentManager::prune() | |
316 | { | |
317 | for (auto it = this->openModels.begin(); it != this->openModels.end(); ++it) | |
318 | { | |
319 | // Find models that are not edited by the user and are not needed by any other model | |
320 | if (true | |
321 | and it->second.opentype == OpenType::AutomaticallyOpened | |
322 | and not this->isReferencedByAnything(it->first) | |
323 | ) { | |
150
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
324 | // Remove its polygon cache |
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
325 | const auto polygonCache = this->polygonCaches.find(it->first); |
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
326 | if (polygonCache != this->polygonCaches.end()) |
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
327 | { |
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
328 | this->polygonCaches.erase(polygonCache); |
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
329 | } |
148 | 330 | // Remove the model |
331 | this->openModels.erase(it); | |
332 | // We need to start over now. It is possible that other models that previously | |
333 | // were referenced by the model we just erased have become prunable. | |
334 | // Moreover, our iterator is invalid now and we cannot continue in this for loop. | |
335 | this->prune(); | |
336 | break; | |
337 | } | |
338 | } | |
339 | } | |
340 | ||
341 | /** | |
342 | * @brief Finds out whether the specified model id is referenced by any other model | |
343 | * @param modelId | |
344 | * @returns bool | |
345 | */ | |
346 | bool DocumentManager::isReferencedByAnything(const ModelId modelId) const | |
347 | { | |
348 | for (auto& haystackModelPair : this->openModels) | |
349 | { | |
350 | if (haystackModelPair.first != modelId) | |
351 | { | |
352 | for (auto& dependencyPair : haystackModelPair.second.dependencies) | |
147 | 353 | { |
148 | 354 | if (dependencyPair.second == modelId) |
355 | { | |
356 | return true; | |
357 | } | |
147 | 358 | } |
148 | 359 | } |
147 | 360 | } |
148 | 361 | return false; |
147 | 362 | } |
363 | ||
150
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
364 | void DocumentManager::makePolygonCacheForModel(const ModelId modelId) |
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
365 | { |
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
366 | Model* model = this->getModelById(modelId); |
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
367 | if (model != nullptr) |
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
368 | { |
193 | 369 | this->polygonCaches[modelId] = {}; |
370 | connect(model, &Model::dataChanged, this, &DocumentManager::modelModified); | |
371 | connect(model, &Model::rowsInserted, this, &DocumentManager::modelModified); | |
372 | connect(model, &Model::rowsRemoved, this, &DocumentManager::modelModified); | |
373 | } | |
374 | } | |
375 | ||
376 | void DocumentManager::modelModified() | |
377 | { | |
195 | 378 | Model* const model = qobject_cast<Model*>(this->sender()); |
194 | 379 | const std::optional<ModelId> modelId = this->findIdForModel(model); |
380 | if (modelId.has_value()) { | |
381 | this->polygonCaches[*modelId].needRecache = true; | |
150
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
382 | } |
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
383 | } |
b6cbba6e29a1
extract polygon cache out of Model
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
384 | |
23
3387a84ddaba
fixed a pile of nonsense that caused subfiles to go haywire
Teemu Piippo <teemu@hecknology.net>
parents:
17
diff
changeset
|
385 | static QString findFile(QString referenceName, const QString& path, const LibraryManager& libraries) |
3387a84ddaba
fixed a pile of nonsense that caused subfiles to go haywire
Teemu Piippo <teemu@hecknology.net>
parents:
17
diff
changeset
|
386 | { |
3387a84ddaba
fixed a pile of nonsense that caused subfiles to go haywire
Teemu Piippo <teemu@hecknology.net>
parents:
17
diff
changeset
|
387 | // Try to find the file in the same place as the model itself |
3387a84ddaba
fixed a pile of nonsense that caused subfiles to go haywire
Teemu Piippo <teemu@hecknology.net>
parents:
17
diff
changeset
|
388 | referenceName.replace("\\", "/"); |
3387a84ddaba
fixed a pile of nonsense that caused subfiles to go haywire
Teemu Piippo <teemu@hecknology.net>
parents:
17
diff
changeset
|
389 | const QDir dir = QFileInfo{path}.dir(); |
3387a84ddaba
fixed a pile of nonsense that caused subfiles to go haywire
Teemu Piippo <teemu@hecknology.net>
parents:
17
diff
changeset
|
390 | QString referencedFilePath = dir.filePath(referenceName); |
3387a84ddaba
fixed a pile of nonsense that caused subfiles to go haywire
Teemu Piippo <teemu@hecknology.net>
parents:
17
diff
changeset
|
391 | if (not QFileInfo{referencedFilePath}.exists()) |
3387a84ddaba
fixed a pile of nonsense that caused subfiles to go haywire
Teemu Piippo <teemu@hecknology.net>
parents:
17
diff
changeset
|
392 | { |
3387a84ddaba
fixed a pile of nonsense that caused subfiles to go haywire
Teemu Piippo <teemu@hecknology.net>
parents:
17
diff
changeset
|
393 | // Look for it in the libraries |
3387a84ddaba
fixed a pile of nonsense that caused subfiles to go haywire
Teemu Piippo <teemu@hecknology.net>
parents:
17
diff
changeset
|
394 | referencedFilePath = libraries.findFile(referenceName); |
3387a84ddaba
fixed a pile of nonsense that caused subfiles to go haywire
Teemu Piippo <teemu@hecknology.net>
parents:
17
diff
changeset
|
395 | } |
3387a84ddaba
fixed a pile of nonsense that caused subfiles to go haywire
Teemu Piippo <teemu@hecknology.net>
parents:
17
diff
changeset
|
396 | return referencedFilePath; |
3387a84ddaba
fixed a pile of nonsense that caused subfiles to go haywire
Teemu Piippo <teemu@hecknology.net>
parents:
17
diff
changeset
|
397 | } |
3387a84ddaba
fixed a pile of nonsense that caused subfiles to go haywire
Teemu Piippo <teemu@hecknology.net>
parents:
17
diff
changeset
|
398 | |
200 | 399 | template<typename T> |
400 | void iterate(const Model& model, std::function<void(const T&)> fn) | |
401 | { | |
402 | for (int i = 0; i < model.size(); ++i) { | |
403 | if (std::holds_alternative<T>(model[i])) { | |
404 | fn(std::get<T>(model[i])); | |
405 | } | |
406 | } | |
407 | } | |
408 | ||
12 | 409 | void DocumentManager::loadDependenciesForModel( |
148 | 410 | const ModelId modelId, |
23
3387a84ddaba
fixed a pile of nonsense that caused subfiles to go haywire
Teemu Piippo <teemu@hecknology.net>
parents:
17
diff
changeset
|
411 | const QString &path, |
148 | 412 | LoadDepedenciesBag& bag) |
12 | 413 | { |
148 | 414 | QSet<QString> failedToOpen; |
12 | 415 | struct LoadingError |
416 | { | |
417 | QString message; | |
418 | }; | |
148 | 419 | bag.processed.insert(modelId); |
420 | if (not this->openModels.contains(modelId)) | |
12 | 421 | { |
148 | 422 | bag.errorStream << tr("bad model ID %1").arg(modelId.value); |
423 | return; | |
424 | } | |
425 | ModelInfo& modelInfo = this->openModels[modelId]; | |
426 | modelInfo.dependencies.clear(); | |
200 | 427 | iterate<Colored<SubfileReference>>(*modelInfo.model, [&](const SubfileReference& ref) { |
428 | const QString referenceName = ref.name; | |
12 | 429 | if (not referenceName.isEmpty() |
148 | 430 | and modelInfo.dependencies.count(referenceName) == 0 |
431 | and not failedToOpen.contains(referenceName)) | |
12 | 432 | { |
433 | try | |
434 | { | |
148 | 435 | const QString referencedFilePath = ::findFile(referenceName, path, bag.libraries); |
23
3387a84ddaba
fixed a pile of nonsense that caused subfiles to go haywire
Teemu Piippo <teemu@hecknology.net>
parents:
17
diff
changeset
|
436 | if (referencedFilePath.isEmpty()) |
12 | 437 | { |
148 | 438 | throw LoadingError{tr("could not find '%1'").arg(referenceName)}; |
12 | 439 | } |
148 | 440 | QString loadErrorString; |
441 | QTextStream localErrorStream{&loadErrorString}; | |
442 | const std::optional<ModelId> modelIdOpt = this->openModel( | |
147 | 443 | referencedFilePath, |
444 | localErrorStream, | |
445 | OpenType::AutomaticallyOpened); | |
148 | 446 | if (not modelIdOpt.has_value()) |
12 | 447 | { |
148 | 448 | const QString& errorMessage = tr("could not load '%1': %2") |
449 | .arg(referencedFilePath) | |
450 | .arg(loadErrorString); | |
451 | throw LoadingError{errorMessage}; | |
12 | 452 | } |
148 | 453 | modelInfo.dependencies[referenceName] = modelIdOpt.value(); |
454 | if (not bag.processed.contains(modelIdOpt.value())) | |
12 | 455 | { |
148 | 456 | this->loadDependenciesForModel(modelIdOpt.value(), referencedFilePath, bag); |
12 | 457 | } |
458 | } | |
459 | catch(const LoadingError& error) | |
460 | { | |
148 | 461 | bag.errorStream << error.message << "\n"; |
462 | failedToOpen.insert(referenceName); | |
463 | bag.missing.append(referenceName); | |
12 | 464 | } |
465 | } | |
200 | 466 | }); |
12 | 467 | } |