21 #include <QMessageBox> |
21 #include <QMessageBox> |
22 #include "documentmanager.h" |
22 #include "documentmanager.h" |
23 #include "lddocument.h" |
23 #include "lddocument.h" |
24 #include "mainwindow.h" |
24 #include "mainwindow.h" |
25 #include "partdownloader.h" |
25 #include "partdownloader.h" |
26 #include "documentloader.h" |
26 #include "parser.h" |
27 #include "glrenderer.h" |
27 #include "glrenderer.h" |
28 |
28 |
29 const QStringList DocumentManager::specialSubdirectories {"s", "48", "8"}; |
29 const QStringList DocumentManager::specialSubdirectories {"s", "48", "8"}; |
30 |
30 |
31 enum |
31 enum |
101 { |
101 { |
102 file = documentToReplace; |
102 file = documentToReplace; |
103 file->clear(); |
103 file->clear(); |
104 } |
104 } |
105 |
105 |
106 bool aborted; |
106 file = openDocument (path, false, false, file); |
107 file = openDocument (path, false, false, file, &aborted); |
|
108 |
107 |
109 if (file == nullptr) |
108 if (file == nullptr) |
110 { |
109 { |
111 if (not aborted) |
110 // Tell the user loading failed. |
112 { |
111 setlocale (LC_ALL, "C"); |
113 // Tell the user loading failed. |
112 QMessageBox::critical(m_window, tr("Error"), format(tr("Failed to open %1: %2"), path, strerror (errno))); |
114 setlocale (LC_ALL, "C"); |
|
115 QMessageBox::critical(m_window, tr("Error"), format(tr("Failed to open %1: %2"), path, strerror (errno))); |
|
116 } |
|
117 |
|
118 m_loadingMainFile = false; |
113 m_loadingMainFile = false; |
119 return; |
114 return; |
120 } |
115 } |
121 |
116 |
122 m_window->openDocumentForEditing(file); |
117 m_window->openDocumentForEditing(file); |
271 |
266 |
272 fp->deleteLater(); |
267 fp->deleteLater(); |
273 return nullptr; |
268 return nullptr; |
274 } |
269 } |
275 |
270 |
276 void DocumentManager::loadFileContents(QIODevice* input, Model& model, int* numWarnings, bool* ok) |
|
277 { |
|
278 if (numWarnings) |
|
279 *numWarnings = 0; |
|
280 |
|
281 DocumentLoader* loader = new DocumentLoader {&model, m_loadingMainFile}; |
|
282 connect(loader, SIGNAL(parseErrorMessage(QString)), this, SLOT(printParseErrorMessage(QString))); |
|
283 loader->read(input); |
|
284 loader->start(); |
|
285 |
|
286 // After start() returns, if the loader isn't done yet, it's delaying |
|
287 // its next iteration through the event loop. We need to catch this here |
|
288 // by telling the event loop to tick, which will tick the file loader again. |
|
289 // We keep doing this until the file loader is ready. |
|
290 while (not loader->isDone()) |
|
291 qApp->processEvents(); |
|
292 |
|
293 // If we wanted the success value, supply that now |
|
294 if (ok) |
|
295 *ok = not loader->hasAborted(); |
|
296 } |
|
297 |
|
298 void DocumentManager::printParseErrorMessage(QString message) |
271 void DocumentManager::printParseErrorMessage(QString message) |
299 { |
272 { |
300 print(message); |
273 print(message); |
301 } |
274 } |
302 |
275 |
303 LDDocument* DocumentManager::openDocument (QString path, bool search, bool implicit, LDDocument* fileToOverride, |
276 LDDocument* DocumentManager::openDocument (QString path, bool search, bool implicit, LDDocument* fileToOverride) |
304 bool* aborted) |
|
305 { |
277 { |
306 // Convert the file name to lowercase when searching because some parts contain subfile |
278 // Convert the file name to lowercase when searching because some parts contain subfile |
307 // subfile references with uppercase file names. I'll assume here that the library will always |
279 // subfile references with uppercase file names. I'll assume here that the library will always |
308 // use lowercase file names for the part files. |
280 // use lowercase file names for the part files. |
309 QFile* fp; |
281 QFile* fp; |
334 |
306 |
335 // Loading the file shouldn't count as actual edits to the document. |
307 // Loading the file shouldn't count as actual edits to the document. |
336 load->history()->setIgnoring (true); |
308 load->history()->setIgnoring (true); |
337 |
309 |
338 int numWarnings; |
310 int numWarnings; |
339 bool ok; |
311 Parser parser {*fp}; |
340 Model model {this}; |
312 load->setHeader(parser.parseHeader()); |
341 loadFileContents(fp, model, &numWarnings, &ok); |
313 parser.parseBody(*load); |
342 load->merge(model); |
|
343 fp->close(); |
314 fp->close(); |
344 fp->deleteLater(); |
315 fp->deleteLater(); |
345 |
316 |
346 if (aborted) |
|
347 *aborted = ok == false; |
|
348 |
|
349 if (not ok) |
|
350 { |
|
351 load->close(); |
|
352 return nullptr; |
|
353 } |
|
354 |
|
355 if (m_loadingMainFile) |
317 if (m_loadingMainFile) |
356 { |
318 { |
|
319 int numWarnings = 0; |
|
320 |
|
321 for (LDObject* object : load->objects()) |
|
322 { |
|
323 if (object->type() == LDObjectType::Error) |
|
324 numWarnings += 1; |
|
325 } |
|
326 |
357 m_window->changeDocument (load); |
327 m_window->changeDocument (load); |
358 print (tr ("File %1 parsed successfully (%2 errors)."), path, numWarnings); |
328 print (tr ("File %1 parsed successfully (%2 errors)."), path, numWarnings); |
359 } |
329 } |
360 |
330 |
361 load->history()->setIgnoring (false); |
331 load->history()->setIgnoring (false); |