18 |
18 |
19 #include <QFile> |
19 #include <QFile> |
20 #include <QDir> |
20 #include <QDir> |
21 #include <QFileInfo> |
21 #include <QFileInfo> |
22 #include <QSaveFile> |
22 #include <QSaveFile> |
|
23 #include <QPlainTextDocumentLayout> |
23 #include <deque> |
24 #include <deque> |
24 #include "src/documentmanager.h" |
25 #include "src/documentmanager.h" |
25 #include "src/parser.h" |
26 #include "src/parser.h" |
26 |
27 |
27 DocumentManager::DocumentManager(QObject *parent) : |
28 DocumentManager::DocumentManager(QObject *parent) : |
28 QObject{parent} |
29 QObject{parent} |
29 { |
30 { |
|
31 } |
|
32 |
|
33 static std::unique_ptr<QTextDocument> newTextDocument() |
|
34 { |
|
35 std::unique_ptr<QTextDocument> newModel = std::make_unique<QTextDocument>(nullptr); |
|
36 newModel->setDocumentLayout(new QPlainTextDocumentLayout{newModel.get()}); |
|
37 return newModel; |
30 } |
38 } |
31 |
39 |
32 /** |
40 /** |
33 * @brief Creates a new model. |
41 * @brief Creates a new model. |
34 * @returns the ID of the new model |
42 * @returns the ID of the new model |
35 */ |
43 */ |
36 ModelId DocumentManager::newModel() |
44 ModelId DocumentManager::newModel() |
37 { |
45 { |
38 const ModelId modelId{++this->modelIdCounter}; |
46 const ModelId modelId{++this->modelIdCounter}; |
39 this->openModels.emplace(std::make_pair(modelId, ModelInfo{ |
47 this->openModels.emplace(std::make_pair(modelId, ModelInfo{ |
40 .model = std::make_unique<Model>(this), |
48 .model = newTextDocument(), |
41 .id = modelId, |
49 .id = modelId, |
42 .opentype = OpenType::ManuallyOpened, |
50 .opentype = OpenType::ManuallyOpened, |
43 })); |
51 })); |
44 this->makePolygonCacheForModel(modelId); |
52 this->makePolygonCacheForModel(modelId); |
45 Q_EMIT this->message(logInfo(tr("New model %1 created").arg(modelId.value))); |
53 Q_EMIT this->message(logInfo(tr("New model %1 created").arg(modelId.value))); |
46 return modelId; |
54 return modelId; |
47 } |
55 } |
48 |
56 |
49 Model* DocumentManager::findDependencyByName(const ModelId modelId, const QString& name) |
57 QTextDocument* DocumentManager::findDependencyByName(const ModelId modelId, const QString& name) |
50 { |
58 { |
51 const auto modelsIterator = this->openModels.find(modelId); |
59 const auto modelsIterator = this->openModels.find(modelId); |
52 if (modelsIterator != std::end(this->openModels)) { |
60 if (modelsIterator != std::end(this->openModels)) { |
53 const auto& dependencies = modelsIterator->second.dependencies; |
61 const auto& dependencies = modelsIterator->second.dependencies; |
54 const auto dependenciesIterator = dependencies.find(name); |
62 const auto dependenciesIterator = dependencies.find(name); |
68 /** |
76 /** |
69 * @brief Gets a model pointer by id or nullptr if not found |
77 * @brief Gets a model pointer by id or nullptr if not found |
70 * @param modelId id of model to find |
78 * @param modelId id of model to find |
71 * @returns model pointer or null |
79 * @returns model pointer or null |
72 */ |
80 */ |
73 Model *DocumentManager::getModelById(ModelId modelId) |
81 QTextDocument *DocumentManager::getModelById(ModelId modelId) |
74 { |
82 { |
75 const auto iterator = this->openModels.find(modelId); |
83 const auto iterator = this->openModels.find(modelId); |
76 if (iterator != this->openModels.end()) |
84 if (iterator != this->openModels.end()) |
77 { |
85 { |
78 return iterator->second.model.get(); |
86 return iterator->second.model.get(); |
109 * @param path Path to the model to open |
117 * @param path Path to the model to open |
110 * @param errorStream Where to write any errors |
118 * @param errorStream Where to write any errors |
111 * @param openType rationale behind opening this file |
119 * @param openType rationale behind opening this file |
112 * @returns model id, or no value on error |
120 * @returns model id, or no value on error |
113 */ |
121 */ |
114 #include <QPlainTextDocumentLayout> |
|
115 std::optional<ModelId> DocumentManager::openModel( |
122 std::optional<ModelId> DocumentManager::openModel( |
116 const QString& path, |
123 const QString& path, |
117 QTextStream& errorStream, |
124 QTextStream& errorStream, |
118 const OpenType openType |
125 const OpenType openType |
119 ) { |
126 ) { |
120 QFile file{path}; |
127 QFile file{path}; |
121 const QString name = pathToName(QFileInfo{path}); |
128 const QString name = pathToName(QFileInfo{path}); |
122 file.open(QFile::ReadOnly | QFile::Text); |
129 file.open(QFile::ReadOnly | QFile::Text); |
123 std::unique_ptr<QTextDocument> newModel = std::make_unique<QTextDocument>(nullptr); |
130 std::unique_ptr<QTextDocument> newModel = newTextDocument(); |
124 newModel->setDocumentLayout(new QPlainTextDocumentLayout{newModel.get()}); |
|
125 newModel->setPlainText(file.readAll()); |
131 newModel->setPlainText(file.readAll()); |
126 std::optional<ModelId> result; |
132 std::optional<ModelId> result; |
127 if (file.error() == QFile::NoError) |
133 if (file.error() == QFile::NoError) |
128 { |
134 { |
129 const ModelId modelId{++this->modelIdCounter}; |
135 const ModelId modelId{++this->modelIdCounter}; |
193 if (info != nullptr) |
199 if (info != nullptr) |
194 { |
200 { |
195 QSaveFile file{info->path}; |
201 QSaveFile file{info->path}; |
196 file.setDirectWriteFallback(true); |
202 file.setDirectWriteFallback(true); |
197 if (file.open(QSaveFile::WriteOnly)) { |
203 if (file.open(QSaveFile::WriteOnly)) { |
198 file.write(info->model->toPlainText().toUtf8()); |
204 file.write(info->model->toPlainText().replace("\n", "\r\n").toUtf8()); |
199 const bool commitSucceeded = file.commit(); |
205 const bool commitSucceeded = file.commit(); |
200 if (not commitSucceeded) { |
206 if (not commitSucceeded) { |
201 errors << QObject::tr("Could not save: %1").arg(file.errorString()); |
207 errors << QObject::tr("Could not save: %1").arg(file.errorString()); |
202 return false; |
208 return false; |
203 } |
209 } |
220 /** |
226 /** |
221 * @brief Searches the open models for the specified model and returns its id if found |
227 * @brief Searches the open models for the specified model and returns its id if found |
222 * @param model model to look for |
228 * @param model model to look for |
223 * @return id or no value if not found |
229 * @return id or no value if not found |
224 */ |
230 */ |
225 std::optional<ModelId> DocumentManager::findIdForModel(const Model *model) const |
231 std::optional<ModelId> DocumentManager::findIdForModel(const QTextDocument *model) const |
226 { |
232 { |
227 std::optional<ModelId> result; |
233 std::optional<ModelId> result; |
228 for (auto it = this->openModels.begin(); it != this->openModels.end(); ++it) |
234 for (auto it = this->openModels.begin(); it != this->openModels.end(); ++it) |
229 { |
235 { |
230 if (it->second.model.get() == model) |
236 if (it->second.model.get() == model) |
317 } |
323 } |
318 } |
324 } |
319 |
325 |
320 void DocumentManager::makePolygonCacheForModel(const ModelId modelId) |
326 void DocumentManager::makePolygonCacheForModel(const ModelId modelId) |
321 { |
327 { |
322 Model* model = this->getModelById(modelId); |
328 QTextDocument* model = this->getModelById(modelId); |
323 if (model != nullptr) |
329 if (model != nullptr) |
324 { |
330 { |
325 const auto modelModified = [this, model]{ |
331 const auto modelModified = [this, model]{ |
326 const std::optional<ModelId> modelId = this->findIdForModel(model); |
332 const std::optional<ModelId> modelId = this->findIdForModel(model); |
327 if (modelId.has_value()) { |
333 if (modelId.has_value()) { |
350 referencedFilePath = libraries.findFile(referenceName); |
356 referencedFilePath = libraries.findFile(referenceName); |
351 } |
357 } |
352 return referencedFilePath; |
358 return referencedFilePath; |
353 } |
359 } |
354 |
360 |
355 static std::set<QString> referenceNames(const Model* model) |
361 static std::set<QString> referenceNames(const QTextDocument* model) |
356 { |
362 { |
357 std::set<QString> result; |
363 std::set<QString> result; |
358 for (const QString& line : model->toPlainText().split("\n")) { |
364 for (const QString& line : model->toPlainText().split("\n")) { |
359 const opt<ParsedLine> parsed = parse(line); |
365 const opt<ParsedLine> parsed = parse(line); |
360 if (parsed.has_value() and std::holds_alternative<LineType1>(*parsed)) { |
366 if (parsed.has_value() and std::holds_alternative<LineType1>(*parsed)) { |