57 QString partsPath, primsPath; |
57 QString partsPath, primsPath; |
58 } pathInfo; |
58 } pathInfo; |
59 |
59 |
60 void initPaths() |
60 void initPaths() |
61 { |
61 { |
62 if (!tryConfigure (io_ldpath)) |
62 if (not tryConfigure (io_ldpath)) |
63 { |
63 { |
64 LDrawPathDialog dlg (false); |
64 LDrawPathDialog dlg (false); |
65 |
65 |
66 if (!dlg.exec()) |
66 if (not dlg.exec()) |
67 exit (0); |
67 exit (0); |
68 |
68 |
69 io_ldpath = dlg.filename(); |
69 io_ldpath = dlg.filename(); |
70 } |
70 } |
71 } |
71 } |
72 |
72 |
73 bool tryConfigure (QString path) |
73 bool tryConfigure (QString path) |
74 { |
74 { |
75 QDir dir; |
75 QDir dir; |
76 |
76 |
77 if (!dir.cd (path)) |
77 if (not dir.cd (path)) |
78 { |
78 { |
79 pathError = "Directory does not exist."; |
79 pathError = "Directory does not exist."; |
80 return false; |
80 return false; |
81 } |
81 } |
82 |
82 |
159 |
159 |
160 // Try find an explicitly loaded file - if we can't find one, |
160 // Try find an explicitly loaded file - if we can't find one, |
161 // we need to create a new file to switch to. |
161 // we need to create a new file to switch to. |
162 for (LDDocument* file : g_loadedFiles) |
162 for (LDDocument* file : g_loadedFiles) |
163 { |
163 { |
164 if (!file->isImplicit()) |
164 if (not file->isImplicit()) |
165 { |
165 { |
166 LDDocument::setCurrent (file); |
166 LDDocument::setCurrent (file); |
167 found = true; |
167 found = true; |
168 break; |
168 break; |
169 } |
169 } |
170 } |
170 } |
171 |
171 |
172 if (!found) |
172 if (not found) |
173 newFile(); |
173 newFile(); |
174 } |
174 } |
175 |
175 |
176 if (this == g_logoedStud) |
176 if (this == g_logoedStud) |
177 g_logoedStud = null; |
177 g_logoedStud = null; |
403 setDone (true); |
403 setDone (true); |
404 return; |
404 return; |
405 } |
405 } |
406 |
406 |
407 // Otherwise, continue, by recursing back. |
407 // Otherwise, continue, by recursing back. |
408 if (!isDone()) |
408 if (not isDone()) |
409 { |
409 { |
410 // If we have a dialog to show progress output to, we cannot just call |
410 // If we have a dialog to show progress output to, we cannot just call |
411 // work() again immediately as the dialog needs some processor cycles as |
411 // work() again immediately as the dialog needs some processor cycles as |
412 // well. Thus, take a detour through the event loop by using the |
412 // well. Thus, take a detour through the event loop by using the |
413 // meta-object system. |
413 // meta-object system. |
443 |
443 |
444 if (numWarnings) |
444 if (numWarnings) |
445 *numWarnings = 0; |
445 *numWarnings = 0; |
446 |
446 |
447 // Read in the lines |
447 // Read in the lines |
448 while (fp->atEnd() == false) |
448 while (not fp->atEnd()) |
449 lines << QString::fromUtf8 (fp->readLine()); |
449 lines << QString::fromUtf8 (fp->readLine()); |
450 |
450 |
451 LDFileLoader* loader = new LDFileLoader; |
451 LDFileLoader* loader = new LDFileLoader; |
452 loader->setWarnings (numWarnings); |
452 loader->setWarnings (numWarnings); |
453 loader->setLines (lines); |
453 loader->setLines (lines); |
456 |
456 |
457 // After start() returns, if the loader isn't done yet, it's delaying |
457 // After start() returns, if the loader isn't done yet, it's delaying |
458 // its next iteration through the event loop. We need to catch this here |
458 // its next iteration through the event loop. We need to catch this here |
459 // by telling the event loop to tick, which will tick the file loader again. |
459 // by telling the event loop to tick, which will tick the file loader again. |
460 // We keep doing this until the file loader is ready. |
460 // We keep doing this until the file loader is ready. |
461 while (loader->isDone() == false) |
461 while (not loader->isDone()) |
462 qApp->processEvents(); |
462 qApp->processEvents(); |
463 |
463 |
464 // If we wanted the success value, supply that now |
464 // If we wanted the success value, supply that now |
465 if (ok) |
465 if (ok) |
466 *ok = !loader->isAborted(); |
466 *ok = not loader->isAborted(); |
467 |
467 |
468 objs = loader->objects(); |
468 objs = loader->objects(); |
469 return objs; |
469 return objs; |
470 } |
470 } |
471 |
471 |
484 else |
484 else |
485 { |
485 { |
486 fp = new QFile (path); |
486 fp = new QFile (path); |
487 fullpath = path; |
487 fullpath = path; |
488 |
488 |
489 if (!fp->open (QIODevice::ReadOnly)) |
489 if (not fp->open (QIODevice::ReadOnly)) |
490 { |
490 { |
491 delete fp; |
491 delete fp; |
492 return null; |
492 return null; |
493 } |
493 } |
494 } |
494 } |
495 |
495 |
496 if (!fp) |
496 if (not fp) |
497 return null; |
497 return null; |
498 |
498 |
499 LDDocument* load = new LDDocument; |
499 LDDocument* load = new LDDocument; |
500 load->setFullPath (fullpath); |
500 load->setFullPath (fullpath); |
501 load->setName (LDDocument::shortenName (load->fullPath())); |
501 load->setName (LDDocument::shortenName (load->fullPath())); |
561 return false; |
561 return false; |
562 |
562 |
563 setName (newpath); |
563 setName (newpath); |
564 } |
564 } |
565 |
565 |
566 if (!save()) |
566 if (not save()) |
567 { |
567 { |
568 message = format (tr ("Failed to save %1 (%2)\nDo you still want to close?"), |
568 message = format (tr ("Failed to save %1 (%2)\nDo you still want to close?"), |
569 name(), strerror (errno)); |
569 name(), strerror (errno)); |
570 |
570 |
571 if (msgbox::critical (g_win, tr ("Save Failure"), message, |
571 if (msgbox::critical (g_win, tr ("Save Failure"), message, |
663 } |
663 } |
664 } |
664 } |
665 |
665 |
666 // We cannot open this file if the document this would replace is not |
666 // We cannot open this file if the document this would replace is not |
667 // safe to close. |
667 // safe to close. |
668 if (documentToReplace != null && documentToReplace->isSafeToClose() == false) |
668 if (documentToReplace != null && not documentToReplace->isSafeToClose()) |
669 { |
669 { |
670 g_loadingMainFile = false; |
670 g_loadingMainFile = false; |
671 return; |
671 return; |
672 } |
672 } |
673 |
673 |
674 LDDocument* file = openDocument (path, false); |
674 LDDocument* file = openDocument (path, false); |
675 |
675 |
676 if (!file) |
676 if (not file) |
677 { |
677 { |
678 // Loading failed, thus drop down to a new file since we |
678 // Loading failed, thus drop down to a new file since we |
679 // closed everything prior. |
679 // closed everything prior. |
680 newFile(); |
680 newFile(); |
681 |
681 |
682 if (!g_aborted) |
682 if (not g_aborted) |
683 { |
683 { |
684 // Tell the user loading failed. |
684 // Tell the user loading failed. |
685 setlocale (LC_ALL, "C"); |
685 setlocale (LC_ALL, "C"); |
686 critical (format (QObject::tr ("Failed to open %1: %2"), path, strerror (errno))); |
686 critical (format (QObject::tr ("Failed to open %1: %2"), path, strerror (errno))); |
687 } |
687 } |
721 |
721 |
722 // ============================================================================= |
722 // ============================================================================= |
723 // |
723 // |
724 bool LDDocument::save (QString savepath) |
724 bool LDDocument::save (QString savepath) |
725 { |
725 { |
726 if (!savepath.length()) |
726 if (not savepath.length()) |
727 savepath = fullPath(); |
727 savepath = fullPath(); |
728 |
728 |
729 QFile f (savepath); |
729 QFile f (savepath); |
730 |
730 |
731 if (!f.open (QIODevice::WriteOnly)) |
731 if (not f.open (QIODevice::WriteOnly)) |
732 return false; |
732 return false; |
733 |
733 |
734 // If the second object in the list holds the file name, update that now. |
734 // If the second object in the list holds the file name, update that now. |
735 // Only do this if the file is explicitly open. |
735 // Only do this if the file is explicitly open. |
736 LDObject* nameObject = getObject (1); |
736 LDObject* nameObject = getObject (1); |
737 |
737 |
738 if (!isImplicit() && nameObject != null && nameObject->type() == LDObject::EComment) |
738 if (not isImplicit() && nameObject != null && nameObject->type() == LDObject::EComment) |
739 { |
739 { |
740 LDComment* nameComment = static_cast<LDComment*> (nameObject); |
740 LDComment* nameComment = static_cast<LDComment*> (nameObject); |
741 |
741 |
742 if (nameComment->text().left (6) == "Name: ") |
742 if (nameComment->text().left (6) == "Name: ") |
743 { |
743 { |
802 |
802 |
803 for (int i = min; i <= max; ++i) |
803 for (int i = min; i <= max; ++i) |
804 { |
804 { |
805 tokens[i].toDouble (&ok); |
805 tokens[i].toDouble (&ok); |
806 |
806 |
807 if (!ok && !scient.exactMatch (tokens[i])) |
807 if (not ok && not scient.exactMatch (tokens[i])) |
808 throw LDParseError (line, format ("Token #%1 was `%2`, expected a number (matched length: %3)", (i + 1), tokens[i], scient.matchedLength())); |
808 { |
|
809 throw LDParseError (line, format ("Token #%1 was `%2`, expected a number (matched length: %3)", |
|
810 (i + 1), tokens[i], scient.matchedLength())); |
|
811 } |
809 } |
812 } |
810 } |
813 } |
811 |
814 |
812 // ============================================================================= |
815 // ============================================================================= |
813 // |
816 // |
836 { |
839 { |
837 // Line was empty, or only consisted of whitespace |
840 // Line was empty, or only consisted of whitespace |
838 return new LDEmpty; |
841 return new LDEmpty; |
839 } |
842 } |
840 |
843 |
841 if (tokens[0].length() != 1 || tokens[0][0].isDigit() == false) |
844 if (tokens[0].length() != 1 || not tokens[0][0].isDigit()) |
842 throw LDParseError (line, "Illogical line code"); |
845 throw LDParseError (line, "Illogical line code"); |
843 |
846 |
844 int num = tokens[0][0].digitValue(); |
847 int num = tokens[0][0].digitValue(); |
845 |
848 |
846 switch (num) |
849 switch (num) |
927 LDDocument* load = getDocument (tokens[14]); |
930 LDDocument* load = getDocument (tokens[14]); |
928 g_loadingMainFile = tmp; |
931 g_loadingMainFile = tmp; |
929 |
932 |
930 // If we cannot open the file, mark it an error. Note we cannot use LDParseError |
933 // If we cannot open the file, mark it an error. Note we cannot use LDParseError |
931 // here because the error object needs the document reference. |
934 // here because the error object needs the document reference. |
932 if (!load) |
935 if (not load) |
933 { |
936 { |
934 LDError* obj = new LDError (line, format ("Could not open %1", tokens[14])); |
937 LDError* obj = new LDError (line, format ("Could not open %1", tokens[14])); |
935 obj->setFileReferenced (tokens[14]); |
938 obj->setFileReferenced (tokens[14]); |
936 return obj; |
939 return obj; |
937 } |
940 } |
1018 { |
1021 { |
1019 // Try find the file in the list of loaded files |
1022 // Try find the file in the list of loaded files |
1020 LDDocument* doc = findDocument (filename); |
1023 LDDocument* doc = findDocument (filename); |
1021 |
1024 |
1022 // If it's not loaded, try open it |
1025 // If it's not loaded, try open it |
1023 if (!doc) |
1026 if (not doc) |
1024 doc = openDocument (filename, true); |
1027 doc = openDocument (filename, true); |
1025 |
1028 |
1026 return doc; |
1029 return doc; |
1027 } |
1030 } |
1028 |
1031 |
1029 // ============================================================================= |
1032 // ============================================================================= |
1030 // |
1033 // |
1031 void reloadAllSubfiles() |
1034 void reloadAllSubfiles() |
1032 { |
1035 { |
1033 if (!getCurrentDocument()) |
1036 if (not getCurrentDocument()) |
1034 return; |
1037 return; |
1035 |
1038 |
1036 g_loadedFiles.clear(); |
1039 g_loadedFiles.clear(); |
1037 g_loadedFiles << getCurrentDocument(); |
1040 g_loadedFiles << getCurrentDocument(); |
1038 |
1041 |
1066 |
1069 |
1067 if (obj->type() == LDObject::EVertex) |
1070 if (obj->type() == LDObject::EVertex) |
1068 m_vertices << obj; |
1071 m_vertices << obj; |
1069 |
1072 |
1070 #ifdef DEBUG |
1073 #ifdef DEBUG |
1071 if (!isImplicit()) |
1074 if (not isImplicit()) |
1072 dprint ("Added object #%1 (%2)\n", obj->id(), obj->typeName()); |
1075 dprint ("Added object #%1 (%2)\n", obj->id(), obj->typeName()); |
1073 #endif |
1076 #endif |
1074 |
1077 |
1075 obj->setDocument (this); |
1078 obj->setDocument (this); |
1076 return getObjectCount() - 1; |
1079 return getObjectCount() - 1; |
1092 history()->add (new AddHistory (pos, obj)); |
1095 history()->add (new AddHistory (pos, obj)); |
1093 m_objects.insert (pos, obj); |
1096 m_objects.insert (pos, obj); |
1094 obj->setDocument (this); |
1097 obj->setDocument (this); |
1095 |
1098 |
1096 #ifdef DEBUG |
1099 #ifdef DEBUG |
1097 if (!isImplicit()) |
1100 if (not isImplicit()) |
1098 dprint ("Inserted object #%1 (%2) at %3\n", obj->id(), obj->typeName(), pos); |
1101 dprint ("Inserted object #%1 (%2) at %3\n", obj->id(), obj->typeName(), pos); |
1099 #endif |
1102 #endif |
1100 } |
1103 } |
1101 |
1104 |
1102 // ============================================================================= |
1105 // ============================================================================= |
1105 { |
1108 { |
1106 int idx = obj->lineNumber(); |
1109 int idx = obj->lineNumber(); |
1107 obj->unselect(); |
1110 obj->unselect(); |
1108 assert (m_objects[idx] == obj); |
1111 assert (m_objects[idx] == obj); |
1109 |
1112 |
1110 if (!history()->isIgnoring()) |
1113 if (not history()->isIgnoring()) |
1111 history()->add (new DelHistory (idx, obj)); |
1114 history()->add (new DelHistory (idx, obj)); |
1112 |
1115 |
1113 m_objects.removeAt (idx); |
1116 m_objects.removeAt (idx); |
1114 obj->setDocument (null); |
1117 obj->setDocument (null); |
1115 } |
1118 } |
1130 void LDDocument::setObject (int idx, LDObject* obj) |
1133 void LDDocument::setObject (int idx, LDObject* obj) |
1131 { |
1134 { |
1132 assert (idx >= 0 && idx < m_objects.size()); |
1135 assert (idx >= 0 && idx < m_objects.size()); |
1133 |
1136 |
1134 // Mark this change to history |
1137 // Mark this change to history |
1135 if (!m_history->isIgnoring()) |
1138 if (not m_history->isIgnoring()) |
1136 { |
1139 { |
1137 QString oldcode = getObject (idx)->asText(); |
1140 QString oldcode = getObject (idx)->asText(); |
1138 QString newcode = obj->asText(); |
1141 QString newcode = obj->asText(); |
1139 *m_history << new EditHistory (idx, oldcode, newcode); |
1142 *m_history << new EditHistory (idx, oldcode, newcode); |
1140 } |
1143 } |
1186 |
1189 |
1187 // ============================================================================= |
1190 // ============================================================================= |
1188 // |
1191 // |
1189 QString LDDocument::getDisplayName() |
1192 QString LDDocument::getDisplayName() |
1190 { |
1193 { |
1191 if (!name().isEmpty()) |
1194 if (not name().isEmpty()) |
1192 return name(); |
1195 return name(); |
1193 |
1196 |
1194 if (!defaultName().isEmpty()) |
1197 if (not defaultName().isEmpty()) |
1195 return "[" + defaultName() + "]"; |
1198 return "[" + defaultName() + "]"; |
1196 |
1199 |
1197 return tr ("<anonymous>"); |
1200 return tr ("<anonymous>"); |
1198 } |
1201 } |
1199 |
1202 |
1225 m_cache.clear(); |
1228 m_cache.clear(); |
1226 doCache = true; |
1229 doCache = true; |
1227 } |
1230 } |
1228 |
1231 |
1229 // If we have this cached, just create a copy of that |
1232 // If we have this cached, just create a copy of that |
1230 if (deep && cache().isEmpty() == false) |
1233 if (deep && not cache().isEmpty()) |
1231 { |
1234 { |
1232 for (LDObject* obj : cache()) |
1235 for (LDObject* obj : cache()) |
1233 objs << obj->createCopy(); |
1236 objs << obj->createCopy(); |
1234 } |
1237 } |
1235 else |
1238 else |
1236 { |
1239 { |
1237 if (!deep) |
1240 if (not deep) |
1238 doCache = false; |
1241 doCache = false; |
1239 |
1242 |
1240 for (LDObject* obj : objects()) |
1243 for (LDObject* obj : objects()) |
1241 { |
1244 { |
1242 // Skip those without scemantic meaning |
1245 // Skip those without scemantic meaning |
1243 if (!obj->isScemantic()) |
1246 if (not obj->isScemantic()) |
1244 continue; |
1247 continue; |
1245 |
1248 |
1246 // Got another sub-file reference, inline it if we're deep-inlining. If not, |
1249 // Got another sub-file reference, inline it if we're deep-inlining. If not, |
1247 // just add it into the objects normally. Also, we only cache immediate |
1250 // just add it into the objects normally. Also, we only cache immediate |
1248 // subfiles and this is not one. Yay, recursion! |
1251 // subfiles and this is not one. Yay, recursion! |
1318 int LDDocument::countExplicitFiles() |
1321 int LDDocument::countExplicitFiles() |
1319 { |
1322 { |
1320 int count = 0; |
1323 int count = 0; |
1321 |
1324 |
1322 for (LDDocument* f : g_loadedFiles) |
1325 for (LDDocument* f : g_loadedFiles) |
1323 if (f->isImplicit() == false) |
1326 { |
1324 count++; |
1327 if (not f->isImplicit()) |
|
1328 ++count; |
|
1329 } |
1325 |
1330 |
1326 return count; |
1331 return count; |
1327 } |
1332 } |
1328 |
1333 |
1329 // ============================================================================= |
1334 // ============================================================================= |
1330 // This little beauty closes the initial file that was open at first when opening |
1335 // This little beauty closes the initial file that was open at first when opening |
1331 // a new file over it. |
1336 // a new file over it. |
1332 // ============================================================================= |
1337 // ============================================================================= |
1333 void LDDocument::closeInitialFile() |
1338 void LDDocument::closeInitialFile() |
1334 { |
1339 { |
1335 if ( |
1340 if (countExplicitFiles() == 2 && |
1336 countExplicitFiles() == 2 && |
|
1337 g_loadedFiles[0]->name().isEmpty() && |
1341 g_loadedFiles[0]->name().isEmpty() && |
1338 g_loadedFiles[1]->name().isEmpty() == false && |
1342 not g_loadedFiles[1]->name().isEmpty() && |
1339 !g_loadedFiles[0]->hasUnsavedChanges() |
1343 not g_loadedFiles[0]->hasUnsavedChanges()) |
1340 ) |
1344 { |
1341 delete g_loadedFiles[0]; |
1345 delete g_loadedFiles[0]; |
|
1346 } |
1342 } |
1347 } |
1343 |
1348 |
1344 // ============================================================================= |
1349 // ============================================================================= |
1345 // |
1350 // |
1346 void loadLogoedStuds() |
1351 void loadLogoedStuds() |
1371 |
1376 |
1372 // ============================================================================= |
1377 // ============================================================================= |
1373 // |
1378 // |
1374 void LDDocument::removeFromSelection (LDObject* obj) // [protected] |
1379 void LDDocument::removeFromSelection (LDObject* obj) // [protected] |
1375 { |
1380 { |
1376 if (!obj->isSelected()) |
1381 if (not obj->isSelected()) |
1377 return; |
1382 return; |
1378 |
1383 |
1379 assert (obj->document() == this); |
1384 assert (obj->document() == this); |
1380 m_sel.removeOne (obj); |
1385 m_sel.removeOne (obj); |
1381 obj->setSelected (false); |
1386 obj->setSelected (false); |