Tue, 01 Mar 2022 17:00:19 +0200
work on edit history
| 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 "modeleditcontext.h" |
| 14 | 25 | #include "linetypes/comment.h" |
| 147 | 26 | #include "linetypes/subfilereference.h" |
|
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
27 | #include "parser.h" |
| 3 | 28 | |
|
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
29 | /** |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
30 | * @brief Constructs a new document manager |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
31 | * @param parent Parent object |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
32 | */ |
| 5 | 33 | DocumentManager::DocumentManager(QObject* parent) : |
| 34 | QObject{parent} | |
| 35 | { | |
| 36 | } | |
| 37 | ||
|
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
38 | /** |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
39 | * @brief Creates a new model. |
| 148 | 40 | * @returns the ID of the new model |
|
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
41 | */ |
| 148 | 42 | ModelId DocumentManager::newModel() |
|
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
43 | { |
| 148 | 44 | const ModelId modelId{++this->modelIdCounter}; |
|
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
45 | const QString name = makeNewModelName(); |
| 148 | 46 | this->openModels[modelId] = ModelInfo{ |
| 47 | .model = std::make_unique<Model>(), | |
| 48 | .opentype = OpenType::ManuallyOpened, | |
| 49 | }; | |
| 50 | return modelId; | |
|
8
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 | /** |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
54 | * @brief Looks for a model by name |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
55 | * @param name Name of the model |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
56 | * @returns model or null |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
57 | */ |
| 148 | 58 | 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
|
59 | { |
| 148 | 60 | const auto modelsIterator = this->openModels.find(modelId); |
| 61 | if (modelsIterator != std::end(this->openModels)) | |
| 62 | { | |
| 63 | const auto& dependencies = modelsIterator->second.dependencies; | |
| 64 | const auto dependenciesIterator = dependencies.find(name); | |
| 65 | if (dependenciesIterator != dependencies.end()) | |
| 66 | { | |
| 67 | ModelInfo& modelInfo = this->openModels[dependenciesIterator->second]; | |
| 68 | return modelInfo.model.get(); | |
| 69 | } | |
| 70 | else | |
| 71 | { | |
| 72 | return nullptr; | |
| 73 | } | |
| 74 | } | |
| 75 | else | |
|
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
76 | { |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
77 | return nullptr; |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
78 | } |
| 148 | 79 | } |
| 80 | ||
| 81 | /** | |
| 82 | * @brief Gets a model pointer by id or nullptr if not found | |
| 83 | * @param modelId id of model to find | |
| 84 | * @returns model pointer or null | |
| 85 | */ | |
| 86 | Model *DocumentManager::getModelById(ModelId modelId) | |
| 87 | { | |
| 88 | const auto iterator = this->openModels.find(modelId); | |
| 89 | if (iterator != this->openModels.end()) | |
| 90 | { | |
| 91 | return iterator->second.model.get(); | |
| 92 | } | |
|
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
93 | else |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
94 | { |
| 148 | 95 | return nullptr; |
|
8
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 | |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
99 | QString pathToName(const QFileInfo& path) |
| 3 | 100 | { |
|
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
101 | static const char* paths[] = { |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
102 | "s", |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
103 | "48" |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
104 | "8" |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
105 | }; |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
106 | const QString baseName = path.fileName(); |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
107 | const QString dirName = QFileInfo{path.dir().path()}.fileName(); |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
108 | QString result; |
| 17 | 109 | 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
|
110 | { |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
111 | result = dirName + "\\" + baseName; |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
112 | } |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
113 | else |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
114 | { |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
115 | result = baseName; |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
116 | } |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
117 | return result; |
| 3 | 118 | } |
|
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
119 | |
| 147 | 120 | /** |
| 121 | * @brief Tries to open the model at the specified path | |
| 122 | * @param path Path to the model to open | |
| 123 | * @param errorStream Where to write any errors | |
| 124 | * @param openType rationale behind opening this file | |
| 148 | 125 | * @returns model id, or no value on error |
| 147 | 126 | */ |
| 148 | 127 | std::optional<ModelId> DocumentManager::openModel( |
| 128 | const QString& path, | |
| 129 | QTextStream& errorStream, | |
| 130 | const OpenType openType | |
| 131 | ) { | |
|
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
132 | QFile file{path}; |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
133 | const QString name = pathToName(path); |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
134 | file.open(QFile::ReadOnly | QFile::Text); |
| 148 | 135 | 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
|
136 | QTextStream textStream{&file}; |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
137 | Model::EditContext editor = newModel->edit(); |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
138 | Parser parser{file}; |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
139 | parser.parseBody(editor); |
| 148 | 140 | std::optional<ModelId> result; |
|
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
141 | if (file.error() == QFile::NoError) |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
142 | { |
| 148 | 143 | const ModelId modelId{++this->modelIdCounter}; |
| 144 | this->openModels[modelId] = {std::move(newModel), path, openType}; | |
| 145 | result = modelId; | |
|
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
146 | } |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
147 | else |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
148 | { |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
149 | errorStream << file.errorString(); |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
150 | } |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
151 | return result; |
|
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 | |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
154 | QString DocumentManager::makeNewModelName() |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
155 | { |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
156 | untitledNameCounter += 1; |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
157 | return "untitled-" + QString::number(untitledNameCounter); |
|
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
5
diff
changeset
|
158 | } |
| 12 | 159 | |
| 148 | 160 | void DocumentManager::loadDependenciesForAllModels(const LibraryManager& libraries, QTextStream& errorStream) |
| 161 | { | |
| 162 | for (const auto& modelInfoPair : this->openModels) | |
| 163 | { | |
| 164 | this->loadDependenciesForModel(modelInfoPair.first, modelInfoPair.second.path, libraries, errorStream); | |
| 165 | } | |
| 166 | } | |
| 167 | ||
| 168 | struct DocumentManager::LoadDepedenciesBag | |
| 169 | { | |
| 170 | const LibraryManager& libraries; | |
| 171 | QStringList missing; | |
| 172 | QSet<ModelId> processed; | |
| 173 | QTextStream& errorStream; | |
| 174 | }; | |
| 175 | ||
| 12 | 176 | void DocumentManager::loadDependenciesForModel( |
| 148 | 177 | 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
|
178 | const QString& path, |
| 12 | 179 | const LibraryManager& libraries, |
| 180 | QTextStream& errorStream) | |
| 181 | { | |
| 148 | 182 | LoadDepedenciesBag bag { |
| 183 | .libraries = libraries, | |
| 184 | .missing = {}, | |
| 185 | .processed = {}, | |
| 186 | .errorStream = errorStream, | |
| 187 | }; | |
| 188 | this->loadDependenciesForModel(modelId, path, bag); | |
| 189 | if (not bag.missing.empty()) | |
| 12 | 190 | { |
| 148 | 191 | bag.missing.sort(Qt::CaseInsensitive); |
| 12 | 192 | errorStream << utility::format( |
| 193 | "The following files could not be opened: %1", | |
| 148 | 194 | bag.missing.join(", ")); |
| 195 | } | |
| 196 | } | |
| 197 | ||
| 198 | void DocumentManager::closeDocument(const ModelId modelId) | |
| 199 | { | |
| 200 | ModelInfo* modelInfo = findInMap(this->openModels, modelId); | |
| 201 | if (modelInfo != nullptr) | |
| 202 | { | |
| 203 | modelInfo->opentype = OpenType::AutomaticallyOpened; | |
| 204 | this->prune(); | |
| 205 | } | |
| 206 | } | |
| 207 | ||
| 208 | const QString *DocumentManager::modelPath(ModelId modelId) const | |
| 209 | { | |
| 210 | const auto iterator = this->openModels.find(modelId); | |
| 211 | if (iterator != this->openModels.end()) | |
| 212 | { | |
| 213 | return &iterator->second.path; | |
| 214 | } | |
| 215 | else | |
| 216 | { | |
| 217 | return nullptr; | |
| 218 | } | |
| 219 | } | |
| 220 | ||
| 221 | /** | |
| 222 | * @brief Changes the path of the specified model. Since the name of the file may change, | |
| 223 | * changing the path can cause dependencies to be resolved differently. As such, dependencies | |
| 224 | * need to be resolved for all files after this operation. | |
| 225 | * @param modelId Model to change the path of | |
| 226 | * @param newPath New path | |
| 227 | * @param libraries Library manager for the purpose of dependency resolving | |
| 228 | * @param errorStream Where to write any errors regarding dependency resolving | |
| 229 | */ | |
| 230 | void DocumentManager::setModelPath( | |
| 231 | const ModelId modelId, | |
| 232 | const QString &newPath, | |
| 233 | const LibraryManager &libraries, | |
| 234 | QTextStream &errorStream) | |
| 235 | { | |
| 236 | auto modelInfoPair = this->openModels.find(modelId); | |
| 237 | if (true | |
| 238 | and modelInfoPair != this->openModels.end() | |
| 239 | and modelInfoPair->second.opentype == OpenType::ManuallyOpened | |
| 240 | ) { | |
| 241 | modelInfoPair->second.path = newPath; | |
| 242 | this->loadDependenciesForAllModels(libraries, errorStream); | |
| 12 | 243 | } |
| 244 | } | |
| 245 | ||
| 148 | 246 | bool DocumentManager::saveModel(const ModelId modelId, QTextStream &errors) |
| 147 | 247 | { |
| 148 | 248 | const QString* const path = this->modelPath(modelId); |
| 249 | if (path != nullptr) | |
| 147 | 250 | { |
| 148 | 251 | QSaveFile file{*path}; |
| 252 | file.setDirectWriteFallback(true); | |
| 253 | if (file.open(QSaveFile::WriteOnly)) | |
| 147 | 254 | { |
| 148 | 255 | // if path is not nullptr, getModelById will always return a value as well |
| 256 | this->getModelById(modelId)->save(&file); | |
| 257 | const bool commitSucceeded = file.commit(); | |
| 258 | if (not commitSucceeded) | |
| 259 | { | |
| 260 | errors << tr("Could not save: %1").arg(file.errorString()); | |
| 261 | return false; | |
| 262 | } | |
| 263 | else | |
| 264 | { | |
| 265 | return true; | |
| 266 | } | |
| 267 | } | |
| 268 | else | |
| 269 | { | |
| 270 | errors << tr("Could not open %1 for writing: %2") | |
| 271 | .arg(file.fileName()) | |
| 272 | .arg(file.errorString()); | |
| 273 | return false; | |
| 147 | 274 | } |
| 275 | } | |
| 148 | 276 | else |
| 277 | { | |
| 278 | errors << tr("Bad model ID %1").arg(modelId.value); | |
| 279 | return false; | |
| 280 | } | |
| 147 | 281 | } |
| 282 | ||
| 148 | 283 | /** |
| 284 | * @brief Searches the open models for the specified model and returns its id if found | |
| 285 | * @param model model to look for | |
| 286 | * @return id or no value if not found | |
| 287 | */ | |
| 288 | std::optional<ModelId> DocumentManager::findIdForModel(const Model *model) const | |
| 147 | 289 | { |
| 148 | 290 | std::optional<ModelId> result; |
| 291 | for (auto it = this->openModels.begin(); it != this->openModels.end(); ++it) | |
| 147 | 292 | { |
| 148 | 293 | if (it->second.model.get() == model) |
| 147 | 294 | { |
| 148 | 295 | result = it->first; |
| 296 | break; | |
| 297 | } | |
| 298 | } | |
| 299 | return result; | |
| 300 | } | |
| 301 | ||
| 302 | /** | |
| 303 | * @brief Cleans up and erases models that are no longer required. | |
| 304 | */ | |
| 305 | void DocumentManager::prune() | |
| 306 | { | |
| 307 | for (auto it = this->openModels.begin(); it != this->openModels.end(); ++it) | |
| 308 | { | |
| 309 | // Find models that are not edited by the user and are not needed by any other model | |
| 310 | if (true | |
| 311 | and it->second.opentype == OpenType::AutomaticallyOpened | |
| 312 | and not this->isReferencedByAnything(it->first) | |
| 313 | ) { | |
| 314 | // Remove the model | |
| 315 | this->openModels.erase(it); | |
| 316 | // We need to start over now. It is possible that other models that previously | |
| 317 | // were referenced by the model we just erased have become prunable. | |
| 318 | // Moreover, our iterator is invalid now and we cannot continue in this for loop. | |
| 319 | this->prune(); | |
| 320 | break; | |
| 321 | } | |
| 322 | } | |
| 323 | } | |
| 324 | ||
| 325 | /** | |
| 326 | * @brief Finds out whether the specified model id is referenced by any other model | |
| 327 | * @param modelId | |
| 328 | * @returns bool | |
| 329 | */ | |
| 330 | bool DocumentManager::isReferencedByAnything(const ModelId modelId) const | |
| 331 | { | |
| 332 | for (auto& haystackModelPair : this->openModels) | |
| 333 | { | |
| 334 | if (haystackModelPair.first != modelId) | |
| 335 | { | |
| 336 | for (auto& dependencyPair : haystackModelPair.second.dependencies) | |
| 147 | 337 | { |
| 148 | 338 | if (dependencyPair.second == modelId) |
| 339 | { | |
| 340 | return true; | |
| 341 | } | |
| 147 | 342 | } |
| 148 | 343 | } |
| 147 | 344 | } |
| 148 | 345 | return false; |
| 147 | 346 | } |
| 347 | ||
|
23
3387a84ddaba
fixed a pile of nonsense that caused subfiles to go haywire
Teemu Piippo <teemu@hecknology.net>
parents:
17
diff
changeset
|
348 | 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
|
349 | { |
|
3387a84ddaba
fixed a pile of nonsense that caused subfiles to go haywire
Teemu Piippo <teemu@hecknology.net>
parents:
17
diff
changeset
|
350 | // 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
|
351 | referenceName.replace("\\", "/"); |
|
3387a84ddaba
fixed a pile of nonsense that caused subfiles to go haywire
Teemu Piippo <teemu@hecknology.net>
parents:
17
diff
changeset
|
352 | 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
|
353 | 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
|
354 | 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
|
355 | { |
|
3387a84ddaba
fixed a pile of nonsense that caused subfiles to go haywire
Teemu Piippo <teemu@hecknology.net>
parents:
17
diff
changeset
|
356 | // 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
|
357 | 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
|
358 | } |
|
3387a84ddaba
fixed a pile of nonsense that caused subfiles to go haywire
Teemu Piippo <teemu@hecknology.net>
parents:
17
diff
changeset
|
359 | return referencedFilePath; |
|
3387a84ddaba
fixed a pile of nonsense that caused subfiles to go haywire
Teemu Piippo <teemu@hecknology.net>
parents:
17
diff
changeset
|
360 | } |
|
3387a84ddaba
fixed a pile of nonsense that caused subfiles to go haywire
Teemu Piippo <teemu@hecknology.net>
parents:
17
diff
changeset
|
361 | |
| 12 | 362 | void DocumentManager::loadDependenciesForModel( |
| 148 | 363 | 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
|
364 | const QString &path, |
| 148 | 365 | LoadDepedenciesBag& bag) |
| 12 | 366 | { |
| 148 | 367 | QSet<QString> failedToOpen; |
| 12 | 368 | struct LoadingError |
| 369 | { | |
| 370 | QString message; | |
| 371 | }; | |
| 148 | 372 | bag.processed.insert(modelId); |
| 373 | if (not this->openModels.contains(modelId)) | |
| 12 | 374 | { |
| 148 | 375 | bag.errorStream << tr("bad model ID %1").arg(modelId.value); |
| 376 | return; | |
| 377 | } | |
| 378 | ModelInfo& modelInfo = this->openModels[modelId]; | |
| 379 | modelInfo.dependencies.clear(); | |
| 380 | for (int i = 0; i < modelInfo.model->size(); i += 1) | |
| 381 | { | |
| 382 | const QString referenceName = modelInfo.model->getObjectProperty(i, ldraw::Property::ReferenceName).toString(); | |
| 12 | 383 | if (not referenceName.isEmpty() |
| 148 | 384 | and modelInfo.dependencies.count(referenceName) == 0 |
| 385 | and not failedToOpen.contains(referenceName)) | |
| 12 | 386 | { |
| 387 | try | |
| 388 | { | |
| 148 | 389 | 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
|
390 | if (referencedFilePath.isEmpty()) |
| 12 | 391 | { |
| 148 | 392 | throw LoadingError{tr("could not find '%1'").arg(referenceName)}; |
| 12 | 393 | } |
| 148 | 394 | QString loadErrorString; |
| 395 | QTextStream localErrorStream{&loadErrorString}; | |
| 396 | const std::optional<ModelId> modelIdOpt = this->openModel( | |
| 147 | 397 | referencedFilePath, |
| 398 | localErrorStream, | |
| 399 | OpenType::AutomaticallyOpened); | |
| 148 | 400 | if (not modelIdOpt.has_value()) |
| 12 | 401 | { |
| 148 | 402 | const QString& errorMessage = tr("could not load '%1': %2") |
| 403 | .arg(referencedFilePath) | |
| 404 | .arg(loadErrorString); | |
| 405 | throw LoadingError{errorMessage}; | |
| 12 | 406 | } |
| 148 | 407 | modelInfo.dependencies[referenceName] = modelIdOpt.value(); |
| 408 | if (not bag.processed.contains(modelIdOpt.value())) | |
| 12 | 409 | { |
| 148 | 410 | this->loadDependenciesForModel(modelIdOpt.value(), referencedFilePath, bag); |
| 12 | 411 | } |
| 412 | } | |
| 413 | catch(const LoadingError& error) | |
| 414 | { | |
| 148 | 415 | bag.errorStream << error.message << "\n"; |
| 416 | failedToOpen.insert(referenceName); | |
| 417 | bag.missing.append(referenceName); | |
| 12 | 418 | } |
| 419 | } | |
| 420 | } | |
| 421 | } |