src/Document.cc

changeset 642
751a8df42842
parent 640
d4dda62c6600
child 644
93dcd1a0e4bd
equal deleted inserted replaced
641:425b169a82aa 642:751a8df42842
44 LDDocument* LDDocument::m_curdoc = null; 44 LDDocument* LDDocument::m_curdoc = null;
45 45
46 const QStringList g_specialSubdirectories ({ "s", "48", "8" }); 46 const QStringList g_specialSubdirectories ({ "s", "48", "8" });
47 47
48 // ============================================================================= 48 // =============================================================================
49 // ============================================================================= 49 //
50 namespace LDPaths 50 namespace LDPaths
51 { 51 {
52 static QString pathError; 52 static QString pathError;
53 53
54 struct 54 struct
117 return pathInfo.partsPath; 117 return pathInfo.partsPath;
118 } 118 }
119 } 119 }
120 120
121 // ============================================================================= 121 // =============================================================================
122 // ============================================================================= 122 //
123 LDDocument::LDDocument() : 123 LDDocument::LDDocument() :
124 m_gldata (new LDGLData) 124 m_gldata (new LDGLData)
125 { 125 {
126 setImplicit (true); 126 setImplicit (true);
127 setSavePosition (-1); 127 setSavePosition (-1);
128 setTabIndex (-1); 128 setTabIndex (-1);
129 setHistory (new History); 129 setHistory (new History);
130 m_History->setDocument (this); 130 history()->setDocument (this);
131 } 131 }
132 132
133 // ============================================================================= 133 // =============================================================================
134 // ============================================================================= 134 //
135 LDDocument::~LDDocument() 135 LDDocument::~LDDocument()
136 { 136 {
137 // Remove this file from the list of files. This MUST be done FIRST, otherwise 137 // Remove this file from the list of files. This MUST be done FIRST, otherwise
138 // a ton of other functions will think this file is still valid when it is not! 138 // a ton of other functions will think this file is still valid when it is not!
139 g_loadedFiles.removeOne (this); 139 g_loadedFiles.removeOne (this);
140 140
141 m_History->setIgnoring (true); 141 m_history->setIgnoring (true);
142 142
143 // Clear everything from the model 143 // Clear everything from the model
144 for (LDObject* obj : getObjects()) 144 for (LDObject* obj : objects())
145 obj->destroy(); 145 obj->destroy();
146 146
147 // Clear the cache as well 147 // Clear the cache as well
148 for (LDObject* obj : getCache()) 148 for (LDObject* obj : cache())
149 obj->destroy(); 149 obj->destroy();
150 150
151 delete m_History; 151 delete m_history;
152 delete m_gldata; 152 delete m_gldata;
153 153
154 // If we just closed the current file, we need to set the current 154 // If we just closed the current file, we need to set the current
155 // file as something else. 155 // file as something else.
156 if (this == getCurrentDocument()) 156 if (this == getCurrentDocument())
177 g_logoedStud = null; 177 g_logoedStud = null;
178 elif (this == g_logoedStud2) 178 elif (this == g_logoedStud2)
179 g_logoedStud2 = null; 179 g_logoedStud2 = null;
180 180
181 g_win->updateDocumentList(); 181 g_win->updateDocumentList();
182 log ("Closed %1", getName()); 182 log ("Closed %1", name());
183 } 183 }
184 184
185 // ============================================================================= 185 // =============================================================================
186 // ============================================================================= 186 //
187 LDDocument* findDocument (QString name) 187 LDDocument* findDocument (QString name)
188 { 188 {
189 for (LDDocument * file : g_loadedFiles) 189 for (LDDocument * file : g_loadedFiles)
190 if (!file->getName().isEmpty() && file->getName() == name) 190 if (!file->name().isEmpty() && file->name() == name)
191 return file; 191 return file;
192 192
193 return null; 193 return null;
194 } 194 }
195 195
196 // ============================================================================= 196 // =============================================================================
197 // ============================================================================= 197 //
198 QString dirname (QString path) 198 QString dirname (QString path)
199 { 199 {
200 long lastpos = path.lastIndexOf (DIRSLASH); 200 long lastpos = path.lastIndexOf (DIRSLASH);
201 201
202 if (lastpos > 0) 202 if (lastpos > 0)
209 209
210 return ""; 210 return "";
211 } 211 }
212 212
213 // ============================================================================= 213 // =============================================================================
214 // ============================================================================= 214 //
215 QString basename (QString path) 215 QString basename (QString path)
216 { 216 {
217 long lastpos = path.lastIndexOf (DIRSLASH); 217 long lastpos = path.lastIndexOf (DIRSLASH);
218 218
219 if (lastpos != -1) 219 if (lastpos != -1)
221 221
222 return path; 222 return path;
223 } 223 }
224 224
225 // ============================================================================= 225 // =============================================================================
226 // ============================================================================= 226 //
227 static QString findLDrawFilePath (QString relpath, bool subdirs) 227 static QString findLDrawFilePath (QString relpath, bool subdirs)
228 { 228 {
229 QString fullPath; 229 QString fullPath;
230 230
231 // LDraw models use Windows-style path separators. If we're not on Windows, 231 // LDraw models use Windows-style path separators. If we're not on Windows,
239 // in the immediate vicinity of a current model to override stock LDraw stuff. 239 // in the immediate vicinity of a current model to override stock LDraw stuff.
240 QString reltop = basename (dirname (relpath)); 240 QString reltop = basename (dirname (relpath));
241 241
242 for (LDDocument* doc : g_loadedFiles) 242 for (LDDocument* doc : g_loadedFiles)
243 { 243 {
244 if (doc->getFullPath().isEmpty()) 244 if (doc->fullPath().isEmpty())
245 continue; 245 continue;
246 246
247 QString partpath = fmt ("%1/%2", dirname (doc->getFullPath()), relpath); 247 QString partpath = fmt ("%1/%2", dirname (doc->fullPath()), relpath);
248 QFile f (partpath); 248 QFile f (partpath);
249 249
250 if (f.exists()) 250 if (f.exists())
251 { 251 {
252 // ensure we don't mix subfiles and 48-primitives with non-subfiles and non-48 252 // ensure we don't mix subfiles and 48-primitives with non-subfiles and non-48
316 fp->deleteLater(); 316 fp->deleteLater();
317 return null; 317 return null;
318 } 318 }
319 319
320 // ============================================================================= 320 // =============================================================================
321 // ============================================================================= 321 //
322 void LDFileLoader::start() 322 void LDFileLoader::start()
323 { 323 {
324 setDone (false); 324 setDone (false);
325 setProgress (0); 325 setProgress (0);
326 setAborted (false); 326 setAborted (false);
332 // Show a progress dialog if we're loading the main Document.here so we can 332 // Show a progress dialog if we're loading the main Document.here so we can
333 // show progress updates and keep the WM posted that we're still here. 333 // show progress updates and keep the WM posted that we're still here.
334 // Of course we cannot exec() the dialog because then the dialog would 334 // Of course we cannot exec() the dialog because then the dialog would
335 // block. 335 // block.
336 dlg = new OpenProgressDialog (g_win); 336 dlg = new OpenProgressDialog (g_win);
337 dlg->setNumLines (getLines().size()); 337 dlg->setNumLines (lines().size());
338 dlg->setModal (true); 338 dlg->setModal (true);
339 dlg->show(); 339 dlg->show();
340 340
341 // Connect the loader in so we can show updates 341 // Connect the loader in so we can show updates
342 connect (this, SIGNAL (workDone()), dlg, SLOT (accept())); 342 connect (this, SIGNAL (workDone()), dlg, SLOT (accept()));
348 // Begin working 348 // Begin working
349 work (0); 349 work (0);
350 } 350 }
351 351
352 // ============================================================================= 352 // =============================================================================
353 // ============================================================================= 353 //
354 void LDFileLoader::work (int i) 354 void LDFileLoader::work (int i)
355 { 355 {
356 // User wishes to abort, so stop here now. 356 // User wishes to abort, so stop here now.
357 if (isAborted()) 357 if (isAborted())
358 { 358 {
359 for (LDObject* obj : m_Objects) 359 for (LDObject* obj : m_objects)
360 obj->destroy(); 360 obj->destroy();
361 361
362 m_Objects.clear(); 362 m_objects.clear();
363 setDone (true); 363 setDone (true);
364 return; 364 return;
365 } 365 }
366 366
367 // Parse up to 300 lines per iteration 367 // Parse up to 300 lines per iteration
368 int max = i + 300; 368 int max = i + 300;
369 369
370 for (; i < max && i < (int) getLines().size(); ++i) 370 for (; i < max && i < (int) lines().size(); ++i)
371 { 371 {
372 QString line = getLines()[i]; 372 QString line = lines()[i];
373 373
374 // Trim the trailing newline 374 // Trim the trailing newline
375 QChar c; 375 QChar c;
376 376
377 while (line.endsWith ("\n") || line.endsWith ("\r")) 377 while (line.endsWith ("\n") || line.endsWith ("\r"))
380 LDObject* obj = parseLine (line); 380 LDObject* obj = parseLine (line);
381 381
382 // Check for parse errors and warn about tthem 382 // Check for parse errors and warn about tthem
383 if (obj->type() == LDObject::EError) 383 if (obj->type() == LDObject::EError)
384 { 384 {
385 log ("Couldn't parse line #%1: %2", getProgress() + 1, static_cast<LDError*> (obj)->reason); 385 log ("Couldn't parse line #%1: %2", progress() + 1, static_cast<LDError*> (obj)->reason());
386 386
387 if (getWarnings() != null) 387 if (warnings() != null)
388 (*getWarnings())++; 388 (*warnings())++;
389 } 389 }
390 390
391 m_Objects << obj; 391 m_objects << obj;
392 setProgress (i); 392 setProgress (i);
393 393
394 // If we have a dialog pointer, update the progress now 394 // If we have a dialog pointer, update the progress now
395 if (isOnForeground()) 395 if (isOnForeground())
396 dlg->updateProgress (i); 396 dlg->updateProgress (i);
397 } 397 }
398 398
399 // If we're done now, tell the environment we're done and stop. 399 // If we're done now, tell the environment we're done and stop.
400 if (i >= ((int) getLines().size()) - 1) 400 if (i >= ((int) lines().size()) - 1)
401 { 401 {
402 emit workDone(); 402 emit workDone();
403 setDone (true); 403 setDone (true);
404 return; 404 return;
405 } 405 }
423 work (i); 423 work (i);
424 } 424 }
425 } 425 }
426 426
427 // ============================================================================= 427 // =============================================================================
428 // ============================================================================= 428 //
429 void LDFileLoader::abort() 429 void LDFileLoader::abort()
430 { 430 {
431 setAborted (true); 431 setAborted (true);
432 432
433 if (isOnForeground()) 433 if (isOnForeground())
434 g_aborted = true; 434 g_aborted = true;
435 } 435 }
436 436
437 // ============================================================================= 437 // =============================================================================
438 // ============================================================================= 438 //
439 LDObjectList loadFileContents (QFile* fp, int* numWarnings, bool* ok) 439 LDObjectList loadFileContents (QFile* fp, int* numWarnings, bool* ok)
440 { 440 {
441 QStringList lines; 441 QStringList lines;
442 LDObjectList objs; 442 LDObjectList objs;
443 443
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 = !loader->isAborted();
467 467
468 objs = loader->getObjects(); 468 objs = loader->objects();
469 return objs; 469 return objs;
470 } 470 }
471 471
472 // ============================================================================= 472 // =============================================================================
473 // ============================================================================= 473 //
474 LDDocument* openDocument (QString path, bool search) 474 LDDocument* openDocument (QString path, bool search)
475 { 475 {
476 // Convert the file name to lowercase since some parts contain uppercase 476 // Convert the file name to lowercase since some parts contain uppercase
477 // file names. I'll assume here that the library will always use lowercase 477 // file names. I'll assume here that the library will always use lowercase
478 // file names for the actual parts.. 478 // file names for the actual parts..
496 if (!fp) 496 if (!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->getFullPath())); 501 load->setName (LDDocument::shortenName (load->fullPath()));
502 dlog ("name: %1 (%2)", load->getName(), load->getFullPath()); 502 dlog ("name: %1 (%2)", load->name(), load->fullPath());
503 g_loadedFiles << load; 503 g_loadedFiles << load;
504 504
505 // Don't take the file loading as actual edits to the file 505 // Don't take the file loading as actual edits to the file
506 load->getHistory()->setIgnoring (true); 506 load->history()->setIgnoring (true);
507 507
508 int numWarnings; 508 int numWarnings;
509 bool ok; 509 bool ok;
510 LDObjectList objs = loadFileContents (fp, &numWarnings, &ok); 510 LDObjectList objs = loadFileContents (fp, &numWarnings, &ok);
511 fp->close(); 511 fp->close();
521 load->addObjects (objs); 521 load->addObjects (objs);
522 522
523 if (g_loadingMainFile) 523 if (g_loadingMainFile)
524 { 524 {
525 LDDocument::setCurrent (load); 525 LDDocument::setCurrent (load);
526 g_win->R()->setFile (load); 526 g_win->R()->setDocument (load);
527 log (QObject::tr ("File %1 parsed successfully (%2 errors)."), path, numWarnings); 527 log (QObject::tr ("File %1 parsed successfully (%2 errors)."), path, numWarnings);
528 } 528 }
529 529
530 load->getHistory()->setIgnoring (false); 530 load->history()->setIgnoring (false);
531 return load; 531 return load;
532 } 532 }
533 533
534 // ============================================================================= 534 // =============================================================================
535 // ============================================================================= 535 //
536 bool LDDocument::isSafeToClose() 536 bool LDDocument::isSafeToClose()
537 { 537 {
538 typedef QMessageBox msgbox; 538 typedef QMessageBox msgbox;
539 setlocale (LC_ALL, "C"); 539 setlocale (LC_ALL, "C");
540 540
541 // If we have unsaved changes, warn and give the option of saving. 541 // If we have unsaved changes, warn and give the option of saving.
542 if (hasUnsavedChanges()) 542 if (hasUnsavedChanges())
543 { 543 {
544 QString message = fmt (tr ("There are unsaved changes to %1. Should it be saved?"), 544 QString message = fmt (tr ("There are unsaved changes to %1. Should it be saved?"),
545 (getName().length() > 0) ? getName() : tr ("<anonymous>")); 545 (name().length() > 0) ? name() : tr ("<anonymous>"));
546 546
547 int button = msgbox::question (g_win, tr ("Unsaved Changes"), message, 547 int button = msgbox::question (g_win, tr ("Unsaved Changes"), message,
548 (msgbox::Yes | msgbox::No | msgbox::Cancel), msgbox::Cancel); 548 (msgbox::Yes | msgbox::No | msgbox::Cancel), msgbox::Cancel);
549 549
550 switch (button) 550 switch (button)
551 { 551 {
552 case msgbox::Yes: 552 case msgbox::Yes:
553 { 553 {
554 // If we don't have a file path yet, we have to ask the user for one. 554 // If we don't have a file path yet, we have to ask the user for one.
555 if (getName().length() == 0) 555 if (name().length() == 0)
556 { 556 {
557 QString newpath = QFileDialog::getSaveFileName (g_win, tr ("Save As"), 557 QString newpath = QFileDialog::getSaveFileName (g_win, tr ("Save As"),
558 getCurrentDocument()->getName(), tr ("LDraw files (*.dat *.ldr)")); 558 getCurrentDocument()->name(), tr ("LDraw files (*.dat *.ldr)"));
559 559
560 if (newpath.length() == 0) 560 if (newpath.length() == 0)
561 return false; 561 return false;
562 562
563 setName (newpath); 563 setName (newpath);
564 } 564 }
565 565
566 if (!save()) 566 if (!save())
567 { 567 {
568 message = fmt (tr ("Failed to save %1 (%2)\nDo you still want to close?"), 568 message = fmt (tr ("Failed to save %1 (%2)\nDo you still want to close?"),
569 getName(), 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,
572 (msgbox::Yes | msgbox::No), msgbox::No) == msgbox::No) 572 (msgbox::Yes | msgbox::No), msgbox::No) == msgbox::No)
573 { 573 {
574 return false; 574 return false;
586 586
587 return true; 587 return true;
588 } 588 }
589 589
590 // ============================================================================= 590 // =============================================================================
591 // ============================================================================= 591 //
592 void closeAll() 592 void closeAll()
593 { 593 {
594 // Remove all loaded files and the objects they contain 594 // Remove all loaded files and the objects they contain
595 QList<LDDocument*> files = g_loadedFiles; 595 QList<LDDocument*> files = g_loadedFiles;
596 596
597 for (LDDocument* file : files) 597 for (LDDocument* file : files)
598 delete file; 598 delete file;
599 } 599 }
600 600
601 // ============================================================================= 601 // =============================================================================
602 // ============================================================================= 602 //
603 void newFile() 603 void newFile()
604 { 604 {
605 // Create a new anonymous file and set it to our current 605 // Create a new anonymous file and set it to our current
606 LDDocument* f = new LDDocument; 606 LDDocument* f = new LDDocument;
607 f->setName (""); 607 f->setName ("");
608 f->setImplicit (false); 608 f->setImplicit (false);
609 g_loadedFiles << f; 609 g_loadedFiles << f;
610 LDDocument::setCurrent (f); 610 LDDocument::setCurrent (f);
611 LDDocument::closeInitialFile(); 611 LDDocument::closeInitialFile();
612 g_win->R()->setFile (f); 612 g_win->R()->setDocument (f);
613 g_win->doFullRefresh(); 613 g_win->doFullRefresh();
614 g_win->updateTitle(); 614 g_win->updateTitle();
615 g_win->updateActions(); 615 g_win->updateActions();
616 } 616 }
617 617
618 // ============================================================================= 618 // =============================================================================
619 // ============================================================================= 619 //
620 void addRecentFile (QString path) 620 void addRecentFile (QString path)
621 { 621 {
622 auto& rfiles = io_recentfiles; 622 auto& rfiles = io_recentfiles;
623 int idx = rfiles.indexOf (path); 623 int idx = rfiles.indexOf (path);
624 624
654 LDDocument* documentToReplace = null; 654 LDDocument* documentToReplace = null;
655 QString shortName = LDDocument::shortenName (path); 655 QString shortName = LDDocument::shortenName (path);
656 656
657 for (LDDocument* doc : g_loadedFiles) 657 for (LDDocument* doc : g_loadedFiles)
658 { 658 {
659 if (doc->getName() == shortName) 659 if (doc->name() == shortName)
660 { 660 {
661 documentToReplace = doc; 661 documentToReplace = doc;
662 break; 662 break;
663 } 663 }
664 } 664 }
693 file->setImplicit (false); 693 file->setImplicit (false);
694 694
695 // Replace references to the old file with the new file. 695 // Replace references to the old file with the new file.
696 if (documentToReplace != null) 696 if (documentToReplace != null)
697 { 697 {
698 for (LDDocumentPointer* ptr : documentToReplace->getReferences()) 698 for (LDDocumentPointer* ptr : documentToReplace->references())
699 { dlog ("ptr: %1 (%2)\n", 699 { dlog ("ptr: %1 (%2)\n",
700 ptr, ptr->getPointer() ? ptr->getPointer()->getName() : "<null>"); 700 ptr, ptr->pointer() ? ptr->pointer()->name() : "<null>");
701 701
702 ptr->operator= (file); 702 *ptr = file;
703 } 703 }
704 704
705 assert (documentToReplace->countReferences() == 0); 705 assert (documentToReplace->references().isEmpty());
706 delete documentToReplace; 706 delete documentToReplace;
707 } 707 }
708 708
709 // If we have an anonymous, unchanged file open as the only open file 709 // If we have an anonymous, unchanged file open as the only open file
710 // (aside of the one we just opened), close it now. 710 // (aside of the one we just opened), close it now.
718 addRecentFile (path); 718 addRecentFile (path);
719 g_loadingMainFile = false; 719 g_loadingMainFile = false;
720 } 720 }
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 (!savepath.length())
727 savepath = getFullPath(); 727 savepath = fullPath();
728 728
729 QFile f (savepath); 729 QFile f (savepath);
730 730
731 if (!f.open (QIODevice::WriteOnly)) 731 if (!f.open (QIODevice::WriteOnly))
732 return false; 732 return false;
737 737
738 if (!isImplicit() && nameObject != null && nameObject->type() == LDObject::EComment) 738 if (!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 {
744 QString newname = shortenName (savepath); 744 QString newname = shortenName (savepath);
745 nameComment->text = fmt ("Name: %1", newname); 745 nameComment->setText (fmt ("Name: %1", newname));
746 g_win->buildObjList(); 746 g_win->buildObjList();
747 } 747 }
748 } 748 }
749 749
750 // File is open, now save the model to it. Note that LDraw requires files to 750 // File is open, now save the model to it. Note that LDraw requires files to
751 // have DOS line endings, so we terminate the lines with \r\n. 751 // have DOS line endings, so we terminate the lines with \r\n.
752 for (LDObject* obj : getObjects()) 752 for (LDObject* obj : objects())
753 f.write ((obj->asText() + "\r\n").toUtf8()); 753 f.write ((obj->asText() + "\r\n").toUtf8());
754 754
755 // File is saved, now clean up. 755 // File is saved, now clean up.
756 f.close(); 756 f.close();
757 757
758 // We have successfully saved, update the save position now. 758 // We have successfully saved, update the save position now.
759 setSavePosition (getHistory()->getPosition()); 759 setSavePosition (history()->position());
760 setFullPath (savepath); 760 setFullPath (savepath);
761 setName (shortenName (savepath)); 761 setName (shortenName (savepath));
762 762
763 g_win->updateDocumentListItem (this); 763 g_win->updateDocumentListItem (this);
764 g_win->updateTitle(); 764 g_win->updateTitle();
765 return true; 765 return true;
766 } 766 }
767 767
768 // ============================================================================= 768 // =============================================================================
769 // ============================================================================= 769 //
770 class LDParseError : public std::exception 770 class LDParseError : public std::exception
771 { 771 {
772 PROPERTY (private, QString, Error, STR_OPS, STOCK_WRITE) 772 PROPERTY (private, QString, error, setError, STOCK_WRITE)
773 PROPERTY (private, QString, Line, STR_OPS, STOCK_WRITE) 773 PROPERTY (private, QString, line, setLine, STOCK_WRITE)
774 774
775 public: 775 public:
776 LDParseError (QString line, QString a) : m_Error (a), m_Line (line) {} 776 LDParseError (QString line, QString a) :
777 m_error (a),
778 m_line (line) {}
777 779
778 const char* what() const throw() 780 const char* what() const throw()
779 { 781 {
780 return getError().toLocal8Bit().constData(); 782 return qPrintable (error());
781 } 783 }
782 }; 784 };
783 785
784 // ============================================================================= 786 // =============================================================================
785 // ============================================================================= 787 //
786 void checkTokenCount (QString line, const QStringList& tokens, int num) 788 void checkTokenCount (QString line, const QStringList& tokens, int num)
787 { 789 {
788 if (tokens.size() != num) 790 if (tokens.size() != num)
789 throw LDParseError (line, fmt ("Bad amount of tokens, expected %1, got %2", num, tokens.size())); 791 throw LDParseError (line, fmt ("Bad amount of tokens, expected %1, got %2", num, tokens.size()));
790 } 792 }
791 793
792 // ============================================================================= 794 // =============================================================================
793 // ============================================================================= 795 //
794 void checkTokenNumbers (QString line, const QStringList& tokens, int min, int max) 796 void checkTokenNumbers (QString line, const QStringList& tokens, int min, int max)
795 { 797 {
796 bool ok; 798 bool ok;
797 799
798 // Check scientific notation, e.g. 7.99361e-15 800 // Check scientific notation, e.g. 7.99361e-15
806 throw LDParseError (line, fmt ("Token #%1 was `%2`, expected a number (matched length: %3)", (i + 1), tokens[i], scient.matchedLength())); 808 throw LDParseError (line, fmt ("Token #%1 was `%2`, expected a number (matched length: %3)", (i + 1), tokens[i], scient.matchedLength()));
807 } 809 }
808 } 810 }
809 811
810 // ============================================================================= 812 // =============================================================================
811 // ============================================================================= 813 //
812 static Vertex parseVertex (QStringList& s, const int n) 814 static Vertex parseVertex (QStringList& s, const int n)
813 { 815 {
814 Vertex v; 816 Vertex v;
815 817
816 for_axes (ax) 818 for_axes (ax)
906 } 908 }
907 } 909 }
908 910
909 // Just a regular comment: 911 // Just a regular comment:
910 LDComment* obj = new LDComment; 912 LDComment* obj = new LDComment;
911 obj->text = comm; 913 obj->setText (comm);
912 return obj; 914 return obj;
913 } 915 }
914 916
915 case 1: 917 case 1:
916 { 918 {
1004 throw LDError (line, "Unknown line code number"); 1006 throw LDError (line, "Unknown line code number");
1005 } 1007 }
1006 } 1008 }
1007 catch (LDParseError& e) 1009 catch (LDParseError& e)
1008 { 1010 {
1009 return new LDError (e.getLine(), e.getError()); 1011 return new LDError (e.line(), e.error());
1010 } 1012 }
1011 } 1013 }
1012 1014
1013 // ============================================================================= 1015 // =============================================================================
1014 // ============================================================================= 1016 //
1015 LDDocument* getDocument (QString filename) 1017 LDDocument* getDocument (QString filename)
1016 { 1018 {
1017 // Try find the file in the list of loaded files 1019 // Try find the file in the list of loaded files
1018 LDDocument* doc = findDocument (filename); 1020 LDDocument* doc = findDocument (filename);
1019 1021
1023 1025
1024 return doc; 1026 return doc;
1025 } 1027 }
1026 1028
1027 // ============================================================================= 1029 // =============================================================================
1028 // ============================================================================= 1030 //
1029 void reloadAllSubfiles() 1031 void reloadAllSubfiles()
1030 { 1032 {
1031 if (!getCurrentDocument()) 1033 if (!getCurrentDocument())
1032 return; 1034 return;
1033 1035
1034 g_loadedFiles.clear(); 1036 g_loadedFiles.clear();
1035 g_loadedFiles << getCurrentDocument(); 1037 g_loadedFiles << getCurrentDocument();
1036 1038
1037 // Go through all objects in the current file and reload the subfiles 1039 // Go through all objects in the current file and reload the subfiles
1038 for (LDObject* obj : getCurrentDocument()->getObjects()) 1040 for (LDObject* obj : getCurrentDocument()->objects())
1039 { 1041 {
1040 if (obj->type() == LDObject::ESubfile) 1042 if (obj->type() == LDObject::ESubfile)
1041 { 1043 {
1042 LDSubfile* ref = static_cast<LDSubfile*> (obj); 1044 LDSubfile* ref = static_cast<LDSubfile*> (obj);
1043 LDDocument* fileInfo = getDocument (ref->getFileInfo()->getName()); 1045 LDDocument* fileInfo = getDocument (ref->fileInfo()->name());
1044 1046
1045 if (fileInfo) 1047 if (fileInfo)
1046 ref->setFileInfo (fileInfo); 1048 ref->setFileInfo (fileInfo);
1047 else 1049 else
1048 ref->replace (new LDError (ref->asText(), fmt ("Could not open %1", ref->getFileInfo()->getName()))); 1050 ref->replace (new LDError (ref->asText(), fmt ("Could not open %1", ref->fileInfo()->name())));
1049 } 1051 }
1050 1052
1051 // Reparse gibberish files. It could be that they are invalid because 1053 // Reparse gibberish files. It could be that they are invalid because
1052 // of loading errors. Circumstances may be different now. 1054 // of loading errors. Circumstances may be different now.
1053 if (obj->type() == LDObject::EError) 1055 if (obj->type() == LDObject::EError)
1054 obj->replace (parseLine (static_cast<LDError*> (obj)->contents)); 1056 obj->replace (parseLine (static_cast<LDError*> (obj)->contents()));
1055 } 1057 }
1056 } 1058 }
1057 1059
1058 // ============================================================================= 1060 // =============================================================================
1059 // ============================================================================= 1061 //
1060 int LDDocument::addObject (LDObject* obj) 1062 int LDDocument::addObject (LDObject* obj)
1061 { 1063 {
1062 getHistory()->add (new AddHistory (getObjects().size(), obj)); 1064 history()->add (new AddHistory (objects().size(), obj));
1063 m_Objects << obj; 1065 m_objects << obj;
1064 1066
1065 if (obj->type() == LDObject::EVertex) 1067 if (obj->type() == LDObject::EVertex)
1066 m_Vertices << obj; 1068 m_vertices << obj;
1067 1069
1068 #ifdef DEBUG 1070 #ifdef DEBUG
1069 if (!isImplicit()) 1071 if (!isImplicit())
1070 dlog ("Added object #%1 (%2)\n", obj->getID(), obj->typeName()); 1072 dlog ("Added object #%1 (%2)\n", obj->id(), obj->typeName());
1071 #endif 1073 #endif
1072 1074
1073 obj->setFile (this); 1075 obj->setDocument (this);
1074 return getObjectCount() - 1; 1076 return getObjectCount() - 1;
1075 } 1077 }
1076 1078
1077 // ============================================================================= 1079 // =============================================================================
1078 // ============================================================================= 1080 //
1079 void LDDocument::addObjects (const LDObjectList objs) 1081 void LDDocument::addObjects (const LDObjectList objs)
1080 { 1082 {
1081 for (LDObject* obj : objs) 1083 for (LDObject* obj : objs)
1082 if (obj) 1084 if (obj)
1083 addObject (obj); 1085 addObject (obj);
1084 } 1086 }
1085 1087
1086 // ============================================================================= 1088 // =============================================================================
1087 // ============================================================================= 1089 //
1088 void LDDocument::insertObj (int pos, LDObject* obj) 1090 void LDDocument::insertObj (int pos, LDObject* obj)
1089 { 1091 {
1090 getHistory()->add (new AddHistory (pos, obj)); 1092 history()->add (new AddHistory (pos, obj));
1091 m_Objects.insert (pos, obj); 1093 m_objects.insert (pos, obj);
1092 obj->setFile (this); 1094 obj->setDocument (this);
1093 1095
1094 #ifdef DEBUG 1096 #ifdef DEBUG
1095 if (!isImplicit()) 1097 if (!isImplicit())
1096 dlog ("Inserted object #%1 (%2) at %3\n", obj->getID(), obj->typeName(), pos); 1098 dlog ("Inserted object #%1 (%2) at %3\n", obj->id(), obj->typeName(), pos);
1097 #endif 1099 #endif
1098 } 1100 }
1099 1101
1100 // ============================================================================= 1102 // =============================================================================
1101 // ============================================================================= 1103 //
1102 void LDDocument::forgetObject (LDObject* obj) 1104 void LDDocument::forgetObject (LDObject* obj)
1103 { 1105 {
1104 int idx = obj->lineNumber(); 1106 int idx = obj->lineNumber();
1105 obj->unselect(); 1107 obj->unselect();
1106 assert (m_Objects[idx] == obj); 1108 assert (m_objects[idx] == obj);
1107 1109
1108 if (!getHistory()->isIgnoring()) 1110 if (!history()->isIgnoring())
1109 getHistory()->add (new DelHistory (idx, obj)); 1111 history()->add (new DelHistory (idx, obj));
1110 1112
1111 m_Objects.removeAt (idx); 1113 m_objects.removeAt (idx);
1112 obj->setFile (null); 1114 obj->setDocument (null);
1113 } 1115 }
1114 1116
1115 // ============================================================================= 1117 // =============================================================================
1116 // ============================================================================= 1118 //
1117 bool safeToCloseAll() 1119 bool safeToCloseAll()
1118 { 1120 {
1119 for (LDDocument* f : g_loadedFiles) 1121 for (LDDocument* f : g_loadedFiles)
1120 if (!f->isSafeToClose()) 1122 if (!f->isSafeToClose())
1121 return false; 1123 return false;
1122 1124
1123 return true; 1125 return true;
1124 } 1126 }
1125 1127
1126 // ============================================================================= 1128 // =============================================================================
1127 // ============================================================================= 1129 //
1128 void LDDocument::setObject (int idx, LDObject* obj) 1130 void LDDocument::setObject (int idx, LDObject* obj)
1129 { 1131 {
1130 assert (idx >= 0 && idx < m_Objects.size()); 1132 assert (idx >= 0 && idx < m_objects.size());
1131 1133
1132 // Mark this change to history 1134 // Mark this change to history
1133 if (!m_History->isIgnoring()) 1135 if (!m_history->isIgnoring())
1134 { 1136 {
1135 QString oldcode = getObject (idx)->asText(); 1137 QString oldcode = getObject (idx)->asText();
1136 QString newcode = obj->asText(); 1138 QString newcode = obj->asText();
1137 *m_History << new EditHistory (idx, oldcode, newcode); 1139 *m_history << new EditHistory (idx, oldcode, newcode);
1138 } 1140 }
1139 1141
1140 m_Objects[idx]->unselect(); 1142 m_objects[idx]->unselect();
1141 m_Objects[idx]->setFile (null); 1143 m_objects[idx]->setDocument (null);
1142 obj->setFile (this); 1144 obj->setDocument (this);
1143 m_Objects[idx] = obj; 1145 m_objects[idx] = obj;
1144 } 1146 }
1145 1147
1146 // ============================================================================= 1148 // =============================================================================
1147 // Close all implicit files with no references 1149 //
1148 // ============================================================================= 1150 // Close all documents we don't need anymore
1151 //
1149 void LDDocument::closeUnused() 1152 void LDDocument::closeUnused()
1150 { 1153 {
1151 for (LDDocument* file : g_loadedFiles) 1154 for (LDDocument* file : g_loadedFiles)
1152 if (file->isImplicit() && file->countReferences() == 0) 1155 if (file->isImplicit() && file->references().isEmpty())
1153 delete file; 1156 delete file;
1154 } 1157 }
1155 1158
1156 // ============================================================================= 1159 // =============================================================================
1157 // ============================================================================= 1160 //
1158 LDObject* LDDocument::getObject (int pos) const 1161 LDObject* LDDocument::getObject (int pos) const
1159 { 1162 {
1160 if (m_Objects.size() <= pos) 1163 if (m_objects.size() <= pos)
1161 return null; 1164 return null;
1162 1165
1163 return m_Objects[pos]; 1166 return m_objects[pos];
1164 } 1167 }
1165 1168
1166 // ============================================================================= 1169 // =============================================================================
1167 // ============================================================================= 1170 //
1168 int LDDocument::getObjectCount() const 1171 int LDDocument::getObjectCount() const
1169 { 1172 {
1170 return getObjects().size(); 1173 return objects().size();
1171 } 1174 }
1172 1175
1173 // ============================================================================= 1176 // =============================================================================
1174 // ============================================================================= 1177 //
1175 bool LDDocument::hasUnsavedChanges() const 1178 bool LDDocument::hasUnsavedChanges() const
1176 { 1179 {
1177 return !isImplicit() && getHistory()->getPosition() != getSavePosition(); 1180 return !isImplicit() && history()->position() != savePosition();
1178 } 1181 }
1179 1182
1180 // ============================================================================= 1183 // =============================================================================
1181 // ============================================================================= 1184 //
1182 QString LDDocument::getDisplayName() 1185 QString LDDocument::getDisplayName()
1183 { 1186 {
1184 if (!getName().isEmpty()) 1187 if (!name().isEmpty())
1185 return getName(); 1188 return name();
1186 1189
1187 if (!getDefaultName().isEmpty()) 1190 if (!defaultName().isEmpty())
1188 return "[" + getDefaultName() + "]"; 1191 return "[" + defaultName() + "]";
1189 1192
1190 return tr ("<anonymous>"); 1193 return tr ("<anonymous>");
1191 } 1194 }
1192 1195
1193 // ============================================================================= 1196 // =============================================================================
1194 // ============================================================================= 1197 //
1195 LDObjectList LDDocument::inlineContents (LDSubfile::InlineFlags flags) 1198 LDObjectList LDDocument::inlineContents (LDSubfile::InlineFlags flags)
1196 { 1199 {
1197 // Possibly substitute with logoed studs: 1200 // Possibly substitute with logoed studs:
1198 // stud.dat -> stud-logo.dat 1201 // stud.dat -> stud-logo.dat
1199 // stud2.dat -> stud-logo2.dat 1202 // stud2.dat -> stud-logo2.dat
1200 if (gl_logostuds && (flags & LDSubfile::RendererInline)) 1203 if (gl_logostuds && (flags & LDSubfile::RendererInline))
1201 { 1204 {
1202 // Ensure logoed studs are loaded first 1205 // Ensure logoed studs are loaded first
1203 loadLogoedStuds(); 1206 loadLogoedStuds();
1204 1207
1205 if (getName() == "stud.dat" && g_logoedStud) 1208 if (name() == "stud.dat" && g_logoedStud)
1206 return g_logoedStud->inlineContents (flags); 1209 return g_logoedStud->inlineContents (flags);
1207 elif (getName() == "stud2.dat" && g_logoedStud2) 1210 elif (name() == "stud2.dat" && g_logoedStud2)
1208 return g_logoedStud2->inlineContents (flags); 1211 return g_logoedStud2->inlineContents (flags);
1209 } 1212 }
1210 1213
1211 LDObjectList objs, objcache; 1214 LDObjectList objs, objcache;
1212 1215
1213 bool deep = flags & LDSubfile::DeepInline, 1216 bool deep = flags & LDSubfile::DeepInline,
1214 doCache = flags & LDSubfile::CacheInline; 1217 doCache = flags & LDSubfile::CacheInline;
1215 1218
1216 if (m_needsCache) 1219 if (m_needsCache)
1217 { 1220 {
1218 clearCache(); 1221 m_cache.clear();
1219 doCache = true; 1222 doCache = true;
1220 } 1223 }
1221 1224
1222 // If we have this cached, just create a copy of that 1225 // If we have this cached, just create a copy of that
1223 if (deep && getCache().isEmpty() == false) 1226 if (deep && cache().isEmpty() == false)
1224 { 1227 {
1225 for (LDObject* obj : getCache()) 1228 for (LDObject* obj : cache())
1226 objs << obj->createCopy(); 1229 objs << obj->createCopy();
1227 } 1230 }
1228 else 1231 else
1229 { 1232 {
1230 if (!deep) 1233 if (!deep)
1231 doCache = false; 1234 doCache = false;
1232 1235
1233 for (LDObject* obj : getObjects()) 1236 for (LDObject* obj : objects())
1234 { 1237 {
1235 // Skip those without scemantic meaning 1238 // Skip those without scemantic meaning
1236 if (!obj->isScemantic()) 1239 if (!obj->isScemantic())
1237 continue; 1240 continue;
1238 1241
1271 1274
1272 return objs; 1275 return objs;
1273 } 1276 }
1274 1277
1275 // ============================================================================= 1278 // =============================================================================
1276 // ============================================================================= 1279 //
1277 LDDocument* LDDocument::current() 1280 LDDocument* LDDocument::current()
1278 { 1281 {
1279 return m_curdoc; 1282 return m_curdoc;
1280 } 1283 }
1281 1284
1298 { 1301 {
1299 // A ton of stuff needs to be updated 1302 // A ton of stuff needs to be updated
1300 g_win->updateDocumentListItem (f); 1303 g_win->updateDocumentListItem (f);
1301 g_win->buildObjList(); 1304 g_win->buildObjList();
1302 g_win->updateTitle(); 1305 g_win->updateTitle();
1303 g_win->R()->setFile (f); 1306 g_win->R()->setDocument (f);
1304 g_win->R()->repaint(); 1307 g_win->R()->repaint();
1305 log ("Changed file to %1", f->getDisplayName()); 1308 log ("Changed file to %1", f->getDisplayName());
1306 } 1309 }
1307 } 1310 }
1308 1311
1309 // ============================================================================= 1312 // =============================================================================
1310 // ============================================================================= 1313 //
1311 int LDDocument::countExplicitFiles() 1314 int LDDocument::countExplicitFiles()
1312 { 1315 {
1313 int count = 0; 1316 int count = 0;
1314 1317
1315 for (LDDocument* f : g_loadedFiles) 1318 for (LDDocument* f : g_loadedFiles)
1325 // ============================================================================= 1328 // =============================================================================
1326 void LDDocument::closeInitialFile() 1329 void LDDocument::closeInitialFile()
1327 { 1330 {
1328 if ( 1331 if (
1329 countExplicitFiles() == 2 && 1332 countExplicitFiles() == 2 &&
1330 g_loadedFiles[0]->getName().isEmpty() && 1333 g_loadedFiles[0]->name().isEmpty() &&
1331 g_loadedFiles[1]->getName().isEmpty() == false && 1334 g_loadedFiles[1]->name().isEmpty() == false &&
1332 !g_loadedFiles[0]->hasUnsavedChanges() 1335 !g_loadedFiles[0]->hasUnsavedChanges()
1333 ) 1336 )
1334 delete g_loadedFiles[0]; 1337 delete g_loadedFiles[0];
1335 } 1338 }
1336 1339
1337 // ============================================================================= 1340 // =============================================================================
1338 // ============================================================================= 1341 //
1339 void loadLogoedStuds() 1342 void loadLogoedStuds()
1340 { 1343 {
1341 if (g_logoedStud && g_logoedStud2) 1344 if (g_logoedStud && g_logoedStud2)
1342 return; 1345 return;
1343 1346
1349 1352
1350 log (LDDocument::tr ("Logoed studs loaded.\n")); 1353 log (LDDocument::tr ("Logoed studs loaded.\n"));
1351 } 1354 }
1352 1355
1353 // ============================================================================= 1356 // =============================================================================
1354 // ============================================================================= 1357 //
1355 void LDDocument::addToSelection (LDObject* obj) // [protected] 1358 void LDDocument::addToSelection (LDObject* obj) // [protected]
1356 { 1359 {
1357 if (obj->isSelected()) 1360 if (obj->isSelected())
1358 return; 1361 return;
1359 1362
1360 assert (obj->getFile() == this); 1363 assert (obj->document() == this);
1361 m_sel << obj; 1364 m_sel << obj;
1362 obj->setSelected (true); 1365 obj->setSelected (true);
1363 } 1366 }
1364 1367
1365 // ============================================================================= 1368 // =============================================================================
1366 // ============================================================================= 1369 //
1367 void LDDocument::removeFromSelection (LDObject* obj) // [protected] 1370 void LDDocument::removeFromSelection (LDObject* obj) // [protected]
1368 { 1371 {
1369 if (!obj->isSelected()) 1372 if (!obj->isSelected())
1370 return; 1373 return;
1371 1374
1372 assert (obj->getFile() == this); 1375 assert (obj->document() == this);
1373 m_sel.removeOne (obj); 1376 m_sel.removeOne (obj);
1374 obj->setSelected (false); 1377 obj->setSelected (false);
1375 } 1378 }
1376 1379
1377 // ============================================================================= 1380 // =============================================================================
1378 // ============================================================================= 1381 //
1379 void LDDocument::clearSelection() 1382 void LDDocument::clearSelection()
1380 { 1383 {
1381 for (LDObject* obj : m_sel) 1384 for (LDObject* obj : m_sel)
1382 removeFromSelection (obj); 1385 removeFromSelection (obj);
1383 1386
1384 assert (m_sel.isEmpty()); 1387 assert (m_sel.isEmpty());
1385 } 1388 }
1386 1389
1387 // ============================================================================= 1390 // =============================================================================
1388 // ============================================================================= 1391 //
1389 const LDObjectList& LDDocument::getSelection() const 1392 const LDObjectList& LDDocument::getSelection() const
1390 { 1393 {
1391 return m_sel; 1394 return m_sel;
1392 } 1395 }
1393 1396
1394 // ============================================================================= 1397 // =============================================================================
1395 // ============================================================================= 1398 //
1396 void LDDocument::swapObjects (LDObject* one, LDObject* other) 1399 void LDDocument::swapObjects (LDObject* one, LDObject* other)
1397 { 1400 {
1398 int a = m_Objects.indexOf (one); 1401 int a = m_objects.indexOf (one);
1399 int b = m_Objects.indexOf (other); 1402 int b = m_objects.indexOf (other);
1400 assert (a != b && a != -1 && b != -1); 1403 assert (a != b && a != -1 && b != -1);
1401 m_Objects[b] = one; 1404 m_objects[b] = one;
1402 m_Objects[a] = other; 1405 m_objects[a] = other;
1403 addToHistory (new SwapHistory (one->getID(), other->getID())); 1406 addToHistory (new SwapHistory (one->id(), other->id()));
1404 } 1407 }
1405 1408
1406 // ============================================================================= 1409 // =============================================================================
1407 // ============================================================================= 1410 //
1408 QString LDDocument::shortenName (QString a) // [static] 1411 QString LDDocument::shortenName (QString a) // [static]
1409 { 1412 {
1410 QString shortname = basename (a); 1413 QString shortname = basename (a);
1411 QString topdirname = basename (dirname (a)); 1414 QString topdirname = basename (dirname (a));
1412 1415
1415 1418
1416 return shortname; 1419 return shortname;
1417 } 1420 }
1418 1421
1419 // ============================================================================= 1422 // =============================================================================
1420 // ============================================================================= 1423 //
1421 void LDDocument::addReference (LDDocumentPointer* ptr) 1424 void LDDocument::addReference (LDDocumentPointer* ptr)
1422 { 1425 {
1423 pushToReferences (ptr); 1426 m_references << ptr;
1424 } 1427 }
1425 1428
1426 // ============================================================================= 1429 // =============================================================================
1427 // ============================================================================= 1430 //
1428 void LDDocument::removeReference (LDDocumentPointer* ptr) 1431 void LDDocument::removeReference (LDDocumentPointer* ptr)
1429 { 1432 {
1430 removeFromReferences (ptr); 1433 m_references.removeOne (ptr);
1431 1434
1432 if (getReferences().size() == 0) 1435 if (references().isEmpty())
1433 invokeLater (closeUnused); 1436 invokeLater (closeUnused);
1434 } 1437 }

mercurial