src/file.cpp

changeset 248
4431371f3ffe
parent 236
b58d35dc5d52
child 249
6b2cc2d82ba6
equal deleted inserted replaced
247:1a2ca515f683 248:4431371f3ffe
17 */ 17 */
18 18
19 #include <QMessageBox> 19 #include <QMessageBox>
20 #include <QFileDialog> 20 #include <QFileDialog>
21 #include <QDir> 21 #include <QDir>
22 #include <qthread.h>
22 23
23 #include <stdlib.h> 24 #include <stdlib.h>
24 #include "common.h" 25 #include "common.h"
25 #include "config.h" 26 #include "config.h"
26 #include "file.h" 27 #include "file.h"
32 #include "gldraw.h" 33 #include "gldraw.h"
33 34
34 cfg (str, io_ldpath, ""); 35 cfg (str, io_ldpath, "");
35 cfg (str, io_recentfiles, ""); 36 cfg (str, io_recentfiles, "");
36 37
38 static bool g_loadingMainFile = false;
39
37 // ============================================================================= 40 // =============================================================================
38 namespace LDPaths { 41 namespace LDPaths {
39 static str pathError; 42 static str pathError;
40 43
41 struct { 44 struct {
100 for (LDObject* obj : m_objCache) 103 for (LDObject* obj : m_objCache)
101 delete obj; 104 delete obj;
102 } 105 }
103 106
104 // ============================================================================= 107 // =============================================================================
105 LDOpenFile* findLoadedFile (str zName) { 108 LDOpenFile* findLoadedFile (str name) {
106 for (LDOpenFile* file : g_loadedFiles) 109 for (LDOpenFile* file : g_loadedFiles)
107 if (file->m_filename == zName) 110 if (file->m_filename == name)
108 return file; 111 return file;
109 112
110 return null; 113 return null;
111 } 114 }
112 115
136 } 139 }
137 140
138 // ============================================================================= 141 // =============================================================================
139 FILE* openLDrawFile (str relpath, bool subdirs) { 142 FILE* openLDrawFile (str relpath, bool subdirs) {
140 printf ("%s: Try to open %s\n", __func__, relpath.c ()); 143 printf ("%s: Try to open %s\n", __func__, relpath.c ());
144
141 #ifndef WIN32 145 #ifndef WIN32
142 relpath.replace ("\\", "/"); 146 relpath.replace ("\\", "/");
143 #endif // WIN32 147 #endif // WIN32
144 148
145 if (g_curfile != null) { 149 if (g_curfile != null) {
185 } 189 }
186 190
187 // ============================================================================= 191 // =============================================================================
188 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 192 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
189 // ============================================================================= 193 // =============================================================================
190 std::vector<LDObject*> loadFileContents (FILE* fp, ulong* numWarnings) { 194 void FileLoader::work () {
191 char line[1024]; 195 char line[1024];
192 vector<str> lines; 196 m_progress = 0;
193 vector<LDObject*> objs; 197 abortflag = false;
194 ulong lnum = 0; 198
195 199 while (fgets (line, sizeof line, filePointer ())) {
196 if (numWarnings)
197 *numWarnings = 0;
198
199 while (fgets (line, sizeof line, fp)) {
200 // Trim the trailing newline 200 // Trim the trailing newline
201 str data = line; 201 str data = line;
202 while (data[~data - 1] == '\n' || data[~data - 1] == '\r') 202 while (data[~data - 1] == '\n' || data[~data - 1] == '\r')
203 data -= 1; 203 data -= 1;
204 204
205 LDObject* obj = parseLine (data); 205 LDObject* obj = parseLine (data);
206 assert (obj != null); 206 assert (obj != null);
207 207
208 // Check for parse errors and warn about tthem 208 // Check for parse errors and warn about tthem
209 if (obj->getType() == LDObject::Gibberish) { 209 if (obj->getType () == LDObject::Gibberish) {
210 logf (LOG_Warning, "Couldn't parse line #%lu: %s\n", 210 logf (LOG_Warning, "Couldn't parse line #%lu: %s\n",
211 lnum, static_cast<LDGibberish*> (obj)->reason.chars()); 211 m_progress + 1, static_cast<LDGibberish*> (obj)->reason.chars());
212 212
213 logf (LOG_Warning, "- Line was: %s\n", data.chars()); 213 logf (LOG_Warning, "- Line was: %s\n", data.chars());
214 214
215 if (numWarnings) 215 if (m_warningsPointer)
216 (*numWarnings)++; 216 (*m_warningsPointer)++;
217 } 217 }
218 218
219 objs.push_back (obj); 219 m_objs.push_back (obj);
220 lnum++; 220 m_progress++;
221 } 221 emit progressUpdate (m_progress);
222
223 if (abortflag) {
224 // We were flagged for abortion, so abort.
225 for (LDObject* obj : m_objs)
226 delete obj;
227
228 m_objs.clear ();
229 return;
230 }
231 }
232
233 emit workDone ();
234 m_done = true;
235 }
236
237 // =============================================================================
238 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
239 // =============================================================================
240 std::vector<LDObject*> loadFileContents (FILE* fp, ulong* numWarnings, bool* ok) {
241 vector<str> lines;
242 vector<LDObject*> objs;
243
244 if (numWarnings)
245 *numWarnings = 0;
246
247 FileLoader* loader = new FileLoader;
248 loader->setFilePointer (fp);
249 loader->setWarningsPointer (numWarnings);
250
251 // Calculate the amount of lines
252 ulong numLines = 0;
253 char line[1024];
254 while (fgets (line, sizeof line, fp))
255 numLines++;
256
257 rewind (fp);
258
259 if (g_loadingMainFile) {
260 // Show a progress dialog if we're loading the main file here and move
261 // the actual work to a separate thread as this can be a rather intensive
262 // operation and if we don't respond quickly enough, the program can be
263 // deemed inresponsive.. which is a bad thing.
264
265 // Init the thread and move the loader into it
266 QThread* loaderThread = new QThread;
267 QObject::connect (loaderThread, SIGNAL (started ()), loader, SLOT (work ()));
268 QObject::connect (loaderThread, SIGNAL (finished ()), loader, SLOT (deleteLater ()));
269 loader->moveToThread (loaderThread);
270 loaderThread->start ();
271
272 // Now create a progress dialog for the operation
273 OpenFileDialog* dlg = new OpenFileDialog (g_win);
274 dlg->setFileName ("???");
275 dlg->setNumLines (numLines);
276
277 // Connect the loader in so we can actually show updates
278 QObject::connect (loader, SIGNAL (progressUpdate (int)), dlg, SLOT (updateProgress (int)));
279 QObject::connect (loader, SIGNAL (workDone ()), dlg, SLOT (accept ()));
280
281 // Show the dialog. If the user hits cancel, tell the loader to abort.
282 if (!dlg->exec ())
283 loader->abortflag = true;
284 } else
285 loader->work ();
286
287 // If we wanted the success value, supply that now
288 if (ok)
289 *ok = loader->done ();
290
291 // If the loader was done, return the objects it generated
292 if (loader->done ())
293 objs = loader->objs ();
222 294
223 return objs; 295 return objs;
224 } 296 }
225 297
226 // ============================================================================= 298 // =============================================================================
227 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 299 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
228 // ============================================================================= 300 // =============================================================================
229 LDOpenFile* openDATFile (str path, bool search, bool mainfile) { 301 LDOpenFile* openDATFile (str path, bool search) {
230 logf ("Opening %s...\n", path.chars()); 302 logf ("Opening %s...\n", path.chars());
231 303
232 // Convert the file name to lowercase since some parts contain uppercase 304 // Convert the file name to lowercase since some parts contain uppercase
233 // file names. I'll assume here that the library will always use lowercase 305 // file names. I'll assume here that the library will always use lowercase
234 // file names for the actual parts.. 306 // file names for the actual parts..
241 if (!fp) { 313 if (!fp) {
242 logf (LOG_Error, "Couldn't open %s: %s\n", path.chars (), strerror (errno)); 314 logf (LOG_Error, "Couldn't open %s: %s\n", path.chars (), strerror (errno));
243 return null; 315 return null;
244 } 316 }
245 317
318 LDOpenFile* oldLoad = g_curfile;
246 LDOpenFile* load = new LDOpenFile; 319 LDOpenFile* load = new LDOpenFile;
247 load->m_filename = path; 320 load->m_filename = path;
248 321
249 if (mainfile) 322 if (g_loadingMainFile)
250 g_curfile = load; 323 g_curfile = load;
251 324
252 ulong numWarnings; 325 ulong numWarnings;
253 std::vector<LDObject*> objs = loadFileContents (fp, &numWarnings); 326 bool ok;
327 std::vector<LDObject*> objs = loadFileContents (fp, &numWarnings, &ok);
328
329 if (!ok) {
330 load = oldLoad;
331 return null;
332 }
254 333
255 for (LDObject* obj : objs) 334 for (LDObject* obj : objs)
256 load->m_objs.push_back (obj); 335 load->m_objs.push_back (obj);
257 336
258 fclose (fp); 337 fclose (fp);
390 469
391 // ============================================================================= 470 // =============================================================================
392 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 471 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
393 // ============================================================================= 472 // =============================================================================
394 void openMainFile (str path) { 473 void openMainFile (str path) {
474 g_loadingMainFile = true;
395 closeAll (); 475 closeAll ();
396 476
397 LDOpenFile* file = openDATFile (path, false, true); 477 LDOpenFile* file = openDATFile (path, false);
398 478
399 if (!file) { 479 if (!file) {
400 // Tell the user loading failed. 480 // Tell the user loading failed.
401 setlocale (LC_ALL, "C"); 481 setlocale (LC_ALL, "C");
402 critical (fmt ("Failed to open %s: %s", path.chars(), strerror (errno))); 482 critical (fmt ("Failed to open %s: %s", path.chars(), strerror (errno)));
483
484 g_loadingMainFile = false;
403 return; 485 return;
404 } 486 }
405 487
406 file->m_implicit = false; 488 file->m_implicit = false;
407 g_curfile = file; 489 g_curfile = file;
416 498
417 History::clear (); 499 History::clear ();
418 500
419 // Add it to the recent files list. 501 // Add it to the recent files list.
420 addRecentFile (path); 502 addRecentFile (path);
503 g_loadingMainFile = false;
421 } 504 }
422 505
423 // ============================================================================= 506 // =============================================================================
424 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 507 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
425 // ============================================================================= 508 // =============================================================================
596 { 679 {
597 // Subfile 680 // Subfile
598 CHECK_TOKEN_COUNT (15) 681 CHECK_TOKEN_COUNT (15)
599 CHECK_TOKEN_NUMBERS (1, 13) 682 CHECK_TOKEN_NUMBERS (1, 13)
600 683
601 // Try open the file 684 // Try open the file. Disable g_loadingMainFile temporarily since we're
602 LDOpenFile* pFile = loadSubfile (tokens[14]); 685 // not loading the main file now, but the subfile
686 bool oldLoadingMainFile = g_loadingMainFile;
687 g_loadingMainFile = false;
688 LDOpenFile* load = loadSubfile (tokens[14]);
689 g_loadingMainFile = oldLoadingMainFile;
603 690
604 // If we cannot open the file, mark it an error 691 // If we cannot open the file, mark it an error
605 if (!pFile) 692 if (!load)
606 return new LDGibberish (line, "Could not open referred file"); 693 return new LDGibberish (line, "Could not open referred file");
607 694
608 LDSubfile* obj = new LDSubfile; 695 LDSubfile* obj = new LDSubfile;
609 obj->color = atol (tokens[1]); 696 obj->color = atol (tokens[1]);
610 obj->pos = parseVertex (tokens, 2); // 2 - 4 697 obj->pos = parseVertex (tokens, 2); // 2 - 4
611 698
612 for (short i = 0; i < 9; ++i) 699 for (short i = 0; i < 9; ++i)
613 obj->transform[i] = atof (tokens[i + 5]); // 5 - 13 700 obj->transform[i] = atof (tokens[i + 5]); // 5 - 13
614 701
615 obj->fileName = tokens[14]; 702 obj->fileName = tokens[14];
616 obj->fileInfo = pFile; 703 obj->fileInfo = load;
617 return obj; 704 return obj;
618 } 705 }
619 706
620 case 2: 707 case 2:
621 { 708 {
681 } 768 }
682 769
683 // ============================================================================= 770 // =============================================================================
684 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 771 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
685 // ============================================================================= 772 // =============================================================================
686 LDOpenFile* loadSubfile (str zFile) { 773 LDOpenFile* loadSubfile (str fname) {
687 // Try open the file 774 // Try find the subfile in the list of loaded files
688 LDOpenFile* pFile = findLoadedFile (zFile); 775 LDOpenFile* load = findLoadedFile (fname);
689 if (!pFile) 776
690 pFile = openDATFile (zFile, true, false); 777 // If it's not loaded, try open it
691 778 if (!load)
692 return pFile; 779 load = openDATFile (fname, true);
780
781 return load;
693 } 782 }
694 783
695 // ============================================================================= 784 // =============================================================================
696 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 785 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
697 // ============================================================================= 786 // =============================================================================
708 g_loadedFiles.push_back (g_curfile); 797 g_loadedFiles.push_back (g_curfile);
709 798
710 // Go through all objects in the current file and reload the subfiles 799 // Go through all objects in the current file and reload the subfiles
711 for (LDObject* obj : g_curfile->m_objs) { 800 for (LDObject* obj : g_curfile->m_objs) {
712 if (obj->getType() == LDObject::Subfile) { 801 if (obj->getType() == LDObject::Subfile) {
713 // Note: ref->pFile is invalid right now since all subfiles were closed. 802 // Note: ref->fileInfo is invalid right now since all subfiles were closed.
714 LDSubfile* ref = static_cast<LDSubfile*> (obj); 803 LDSubfile* ref = static_cast<LDSubfile*> (obj);
715 LDOpenFile* pFile = loadSubfile (ref->fileName); 804 LDOpenFile* fileInfo = loadSubfile (ref->fileName);
716 805
717 if (pFile) 806 if (fileInfo)
718 ref->fileInfo = pFile; 807 ref->fileInfo = fileInfo;
719 else { 808 else {
720 // Couldn't load the file, mark it an error 809 // Couldn't load the file, mark it an error
721 ref->replace (new LDGibberish (ref->getContents (), "Could not open referred file")); 810 ref->replace (new LDGibberish (ref->getContents (), "Could not open referred file"));
722 } 811 }
723 } 812 }
724 813
725 // Reparse gibberish files. It could be that they are invalid because 814 // Reparse gibberish files. It could be that they are invalid because
726 // the file could not be opened. Circumstances may be different now. 815 // of loading errors. Circumstances may be different now.
727 if (obj->getType() == LDObject::Gibberish) 816 if (obj->getType() == LDObject::Gibberish)
728 obj->replace (parseLine (static_cast<LDGibberish*> (obj)->contents)); 817 obj->replace (parseLine (static_cast<LDGibberish*> (obj)->contents));
729 } 818 }
730 } 819 }
731 820

mercurial