src/ldDocument.cpp

changeset 1217
314e12e23c3a
parent 1011
4fdd74a04790
child 1222
34def2630300
equal deleted inserted replaced
1216:12f9ea615cbc 1217:314e12e23c3a
32 #include "ldpaths.h" 32 #include "ldpaths.h"
33 #include "documentloader.h" 33 #include "documentloader.h"
34 #include "dialogs/openprogressdialog.h" 34 #include "dialogs/openprogressdialog.h"
35 #include "documentmanager.h" 35 #include "documentmanager.h"
36 36
37 LDDocument::LDDocument (DocumentManager* parent) : 37 LDDocument::LDDocument(DocumentManager* parent) :
38 QObject (parent), 38 QObject(parent),
39 HierarchyElement (parent), 39 HierarchyElement(parent),
40 m_history (new EditHistory (this)), 40 m_history(new EditHistory(this)),
41 m_isCache (true), 41 m_isCache(true),
42 m_verticesOutdated (true), 42 m_verticesOutdated(true),
43 m_needVertexMerge (true), 43 m_needVertexMerge(true),
44 m_beingDestroyed (false), 44 m_beingDestroyed(false),
45 m_gldata (new LDGLData), 45 m_gldata(new LDGLData),
46 m_manager (parent) 46 m_manager(parent)
47 { 47 {
48 setSavePosition (-1); 48 setSavePosition(-1);
49 setTabIndex (-1); 49 setTabIndex(-1);
50 m_needsReCache = true; 50 m_needsReCache = true;
51 } 51 }
52 52
53 LDDocument::~LDDocument() 53 LDDocument::~LDDocument()
54 { 54 {
64 QString LDDocument::name() const 64 QString LDDocument::name() const
65 { 65 {
66 return m_name; 66 return m_name;
67 } 67 }
68 68
69 void LDDocument::setName (QString value) 69 void LDDocument::setName(QString value)
70 { 70 {
71 m_name = value; 71 m_name = value;
72 } 72 }
73 73
74 const LDObjectList& LDDocument::objects() const 74 const LDObjectList& LDDocument::objects() const
84 QString LDDocument::fullPath() 84 QString LDDocument::fullPath()
85 { 85 {
86 return m_fullPath; 86 return m_fullPath;
87 } 87 }
88 88
89 void LDDocument::setFullPath (QString value) 89 void LDDocument::setFullPath(QString value)
90 { 90 {
91 m_fullPath = value; 91 m_fullPath = value;
92 } 92 }
93 93
94 int LDDocument::tabIndex() const 94 int LDDocument::tabIndex() const
95 { 95 {
96 return m_tabIndex; 96 return m_tabIndex;
97 } 97 }
98 98
99 void LDDocument::setTabIndex (int value) 99 void LDDocument::setTabIndex(int value)
100 { 100 {
101 m_tabIndex = value; 101 m_tabIndex = value;
102 } 102 }
103 103
104 const QList<LDPolygon>& LDDocument::polygonData() const 104 const QList<LDPolygon>& LDDocument::polygonData() const
109 long LDDocument::savePosition() const 109 long LDDocument::savePosition() const
110 { 110 {
111 return m_savePosition; 111 return m_savePosition;
112 } 112 }
113 113
114 void LDDocument::setSavePosition (long value) 114 void LDDocument::setSavePosition(long value)
115 { 115 {
116 m_savePosition = value; 116 m_savePosition = value;
117 } 117 }
118 118
119 QString LDDocument::defaultName() const 119 QString LDDocument::defaultName() const
120 { 120 {
121 return m_defaultName; 121 return m_defaultName;
122 } 122 }
123 123
124 void LDDocument::setDefaultName (QString value) 124 void LDDocument::setDefaultName(QString value)
125 { 125 {
126 m_defaultName = value; 126 m_defaultName = value;
127 } 127 }
128 128
129 void LDDocument::openForEditing() 129 void LDDocument::openForEditing()
130 { 130 {
131 if (m_isCache) 131 if (m_isCache)
132 { 132 {
133 m_isCache = false; 133 m_isCache = false;
134 print ("Opened %1", name()); 134 print("Opened %1", name());
135 135
136 // Cache files are not compiled by the GL renderer. Now that this file is open for editing, it needs to be 136 // Cache files are not compiled by the GL renderer. Now that this file is open for editing, it needs to be
137 // compiled. 137 // compiled.
138 m_window->renderer()->compiler()->compileDocument (this); 138 m_window->renderer()->compiler()->compileDocument(this);
139 m_window->updateDocumentList(); 139 m_window->updateDocumentList();
140 } 140 }
141 } 141 }
142 142
143 bool LDDocument::isCache() const 143 bool LDDocument::isCache() const
163 void LDDocument::clearHistory() 163 void LDDocument::clearHistory()
164 { 164 {
165 history()->clear(); 165 history()->clear();
166 } 166 }
167 167
168 void LDDocument::addToHistory (AbstractHistoryEntry* entry) 168 void LDDocument::addToHistory(AbstractHistoryEntry* entry)
169 { 169 {
170 history()->add (entry); 170 history()->add(entry);
171 } 171 }
172 172
173 void LDDocument::close() 173 void LDDocument::close()
174 { 174 {
175 if (not isCache()) 175 if (not isCache())
176 { 176 {
177 m_isCache = true; 177 m_isCache = true;
178 print ("Closed %1", name()); 178 print("Closed %1", name());
179 m_window->updateDocumentList(); 179 m_window->updateDocumentList();
180 180
181 // If the current document just became implicit (i.e. user closed it), we need to get a new one to show. 181 // If the current document just became implicit(i.e. user closed it), we need to get a new one to show.
182 if (currentDocument() == this) 182 if (currentDocument() == this)
183 m_window->currentDocumentClosed(); 183 m_window->currentDocumentClosed();
184 } 184 }
185 } 185 }
186 186
194 // Performs safety checks. Do this before closing any files! 194 // Performs safety checks. Do this before closing any files!
195 // 195 //
196 bool LDDocument::isSafeToClose() 196 bool LDDocument::isSafeToClose()
197 { 197 {
198 using msgbox = QMessageBox; 198 using msgbox = QMessageBox;
199 setlocale (LC_ALL, "C"); 199 setlocale(LC_ALL, "C");
200 200
201 // If we have unsaved changes, warn and give the option of saving. 201 // If we have unsaved changes, warn and give the option of saving.
202 if (hasUnsavedChanges()) 202 if (hasUnsavedChanges())
203 { 203 {
204 QString message = format (tr ("There are unsaved changes to %1. Should it be saved?"), getDisplayName()); 204 QString message = format(tr("There are unsaved changes to %1. Should it be saved?"), getDisplayName());
205 205
206 int button = msgbox::question (m_window, QObject::tr ("Unsaved Changes"), message, 206 int button = msgbox::question(m_window, QObject::tr("Unsaved Changes"), message,
207 (msgbox::Yes | msgbox::No | msgbox::Cancel), msgbox::Cancel); 207 (msgbox::Yes | msgbox::No | msgbox::Cancel), msgbox::Cancel);
208 208
209 switch (button) 209 switch(button)
210 { 210 {
211 case msgbox::Yes: 211 case msgbox::Yes:
212 { 212 {
213 // If we don't have a file path yet, we have to ask the user for one. 213 // If we don't have a file path yet, we have to ask the user for one.
214 if (name().length() == 0) 214 if (name().length() == 0)
215 { 215 {
216 QString newpath = QFileDialog::getSaveFileName (m_window, QObject::tr ("Save As"), 216 QString newpath = QFileDialog::getSaveFileName(m_window, QObject::tr("Save As"),
217 name(), QObject::tr ("LDraw files (*.dat *.ldr)")); 217 name(), QObject::tr("LDraw files(*.dat *.ldr)"));
218 218
219 if (newpath.length() == 0) 219 if (newpath.length() == 0)
220 return false; 220 return false;
221 221
222 setName (newpath); 222 setName(newpath);
223 } 223 }
224 224
225 if (not save()) 225 if (not save())
226 { 226 {
227 message = format (QObject::tr ("Failed to save %1 (%2)\nDo you still want to close?"), 227 message = format(QObject::tr("Failed to save %1(%2)\nDo you still want to close?"),
228 name(), strerror (errno)); 228 name(), strerror(errno));
229 229
230 if (msgbox::critical (m_window, QObject::tr ("Save Failure"), message, 230 if (msgbox::critical(m_window, QObject::tr("Save Failure"), message,
231 (msgbox::Yes | msgbox::No), msgbox::No) == msgbox::No) 231 (msgbox::Yes | msgbox::No), msgbox::No) == msgbox::No)
232 { 232 {
233 return false; 233 return false;
234 } 234 }
235 } 235 }
247 return true; 247 return true;
248 } 248 }
249 249
250 // ============================================================================= 250 // =============================================================================
251 // 251 //
252 bool LDDocument::save (QString path, int64* sizeptr) 252 bool LDDocument::save(QString path, int64* sizeptr)
253 { 253 {
254 if (isCache()) 254 if (isCache())
255 return false; 255 return false;
256 256
257 if (not path.length()) 257 if (not path.length())
258 path = fullPath(); 258 path = fullPath();
259 259
260 // If the second object in the list holds the file name, update that now. 260 // If the second object in the list holds the file name, update that now.
261 LDObject* nameObject = getObject (1); 261 LDObject* nameObject = getObject(1);
262 262
263 if (nameObject and nameObject->type() == OBJ_Comment) 263 if (nameObject and nameObject->type() == OBJ_Comment)
264 { 264 {
265 LDComment* nameComment = static_cast<LDComment*> (nameObject); 265 LDComment* nameComment = static_cast<LDComment*>(nameObject);
266 266
267 if (nameComment->text().left (6) == "Name: ") 267 if (nameComment->text().left(6) == "Name: ")
268 { 268 {
269 QString newname = shortenName (path); 269 QString newname = shortenName(path);
270 nameComment->setText (format ("Name: %1", newname)); 270 nameComment->setText(format("Name: %1", newname));
271 m_window->buildObjectList(); 271 m_window->buildObjectList();
272 } 272 }
273 } 273 }
274 274
275 QByteArray data; 275 QByteArray data;
278 *sizeptr = 0; 278 *sizeptr = 0;
279 279
280 // File is open, now save the model to it. Note that LDraw requires files to have DOS line endings. 280 // File is open, now save the model to it. Note that LDraw requires files to have DOS line endings.
281 for (LDObject* obj : objects()) 281 for (LDObject* obj : objects())
282 { 282 {
283 QByteArray subdata ((obj->asText() + "\r\n").toUtf8()); 283 QByteArray subdata((obj->asText() + "\r\n").toUtf8());
284 data.append (subdata); 284 data.append(subdata);
285 285
286 if (sizeptr) 286 if (sizeptr)
287 *sizeptr += subdata.size(); 287 *sizeptr += subdata.size();
288 } 288 }
289 289
290 QFile f (path); 290 QFile f(path);
291 291
292 if (not f.open (QIODevice::WriteOnly)) 292 if (not f.open(QIODevice::WriteOnly))
293 return false; 293 return false;
294 294
295 f.write (data); 295 f.write(data);
296 f.close(); 296 f.close();
297 297
298 // We have successfully saved, update the save position now. 298 // We have successfully saved, update the save position now.
299 setSavePosition (history()->position()); 299 setSavePosition(history()->position());
300 setFullPath (path); 300 setFullPath(path);
301 setName (shortenName (path)); 301 setName(shortenName(path));
302 m_window->updateDocumentListItem (this); 302 m_window->updateDocumentListItem(this);
303 m_window->updateTitle(); 303 m_window->updateTitle();
304 return true; 304 return true;
305 } 305 }
306 306
307 // ============================================================================= 307 // =============================================================================
308 // 308 //
309 void LDDocument::clear() 309 void LDDocument::clear()
310 { 310 {
311 for (LDObject* obj : objects()) 311 for (LDObject* obj : objects())
312 forgetObject (obj); 312 forgetObject(obj);
313 } 313 }
314 314
315 // ============================================================================= 315 // =============================================================================
316 // 316 //
317 static void CheckTokenCount (const QStringList& tokens, int num) 317 static void CheckTokenCount(const QStringList& tokens, int num)
318 { 318 {
319 if (tokens.size() != num) 319 if (tokens.size() != num)
320 throw QString (format ("Bad amount of tokens, expected %1, got %2", num, tokens.size())); 320 throw QString(format("Bad amount of tokens, expected %1, got %2", num, tokens.size()));
321 } 321 }
322 322
323 // ============================================================================= 323 // =============================================================================
324 // 324 //
325 static void CheckTokenNumbers (const QStringList& tokens, int min, int max) 325 static void CheckTokenNumbers(const QStringList& tokens, int min, int max)
326 { 326 {
327 bool ok; 327 bool ok;
328 QRegExp scientificRegex ("\\-?[0-9]+\\.[0-9]+e\\-[0-9]+"); 328 QRegExp scientificRegex("\\-?[0-9]+\\.[0-9]+e\\-[0-9]+");
329 329
330 for (int i = min; i <= max; ++i) 330 for (int i = min; i <= max; ++i)
331 { 331 {
332 // Check for floating point 332 // Check for floating point
333 tokens[i].toDouble (&ok); 333 tokens[i].toDouble(&ok);
334 if (ok) 334 if (ok)
335 return; 335 return;
336 336
337 // Check hex 337 // Check hex
338 if (tokens[i].startsWith ("0x")) 338 if (tokens[i].startsWith("0x"))
339 { 339 {
340 tokens[i].mid (2).toInt (&ok, 16); 340 tokens[i].mid(2).toInt(&ok, 16);
341 341
342 if (ok) 342 if (ok)
343 return; 343 return;
344 } 344 }
345 345
346 // Check scientific notation, e.g. 7.99361e-15 346 // Check scientific notation, e.g. 7.99361e-15
347 if (scientificRegex.exactMatch (tokens[i])) 347 if (scientificRegex.exactMatch(tokens[i]))
348 return; 348 return;
349 349
350 throw QString (format ("Token #%1 was `%2`, expected a number (matched length: %3)", 350 throw QString(format("Token #%1 was `%2`, expected a number(matched length: %3)",
351 (i + 1), tokens[i], scientificRegex.matchedLength())); 351 (i + 1), tokens[i], scientificRegex.matchedLength()));
352 } 352 }
353 } 353 }
354 354
355 // ============================================================================= 355 // =============================================================================
356 // 356 //
357 static Vertex ParseVertex (QStringList& s, const int n) 357 static Vertex ParseVertex(QStringList& s, const int n)
358 { 358 {
359 Vertex v; 359 Vertex v;
360 v.apply ([&] (Axis ax, double& a) { a = s[n + ax].toDouble(); }); 360 v.apply([&](Axis ax, double& a) { a = s[n + ax].toDouble(); });
361 return v; 361 return v;
362 } 362 }
363 363
364 static int32 StringToNumber (QString a, bool* ok = nullptr) 364 static int32 StringToNumber(QString a, bool* ok = nullptr)
365 { 365 {
366 int base = 10; 366 int base = 10;
367 367
368 if (a.startsWith ("0x")) 368 if (a.startsWith("0x"))
369 { 369 {
370 a.remove (0, 2); 370 a.remove(0, 2);
371 base = 16; 371 base = 16;
372 } 372 }
373 373
374 return a.toLong (ok, base); 374 return a.toLong(ok, base);
375 } 375 }
376 376
377 // ============================================================================= 377 // =============================================================================
378 // This is the LDraw code parser function. It takes in a string containing LDraw 378 // This is the LDraw code parser function. It takes in a string containing LDraw
379 // code and returns the object parsed from it. parseLine never returns null, 379 // code and returns the object parsed from it. parseLine never returns null,
380 // the object will be LDError if it could not be parsed properly. 380 // the object will be LDError if it could not be parsed properly.
381 // ============================================================================= 381 // =============================================================================
382 LDObject* ParseLine (QString line) 382 LDObject* ParseLine(QString line)
383 { 383 {
384 try 384 try
385 { 385 {
386 QStringList tokens = line.split (" ", QString::SkipEmptyParts); 386 QStringList tokens = line.split(" ", QString::SkipEmptyParts);
387 387
388 if (tokens.size() <= 0) 388 if (tokens.size() <= 0)
389 { 389 {
390 // Line was empty, or only consisted of whitespace 390 // Line was empty, or only consisted of whitespace
391 return LDSpawn<LDEmpty>(); 391 return LDSpawn<LDEmpty>();
392 } 392 }
393 393
394 if (tokens[0].length() != 1 or not tokens[0][0].isDigit()) 394 if (tokens[0].length() != 1 or not tokens[0][0].isDigit())
395 throw QString ("Illogical line code"); 395 throw QString("Illogical line code");
396 396
397 int num = tokens[0][0].digitValue(); 397 int num = tokens[0][0].digitValue();
398 398
399 switch (num) 399 switch(num)
400 { 400 {
401 case 0: 401 case 0:
402 { 402 {
403 // Comment 403 // Comment
404 QString commentText (line.mid (line.indexOf ("0") + 2)); 404 QString commentText(line.mid(line.indexOf("0") + 2));
405 QString commentTextSimplified (commentText.simplified()); 405 QString commentTextSimplified(commentText.simplified());
406 406
407 // Handle BFC statements 407 // Handle BFC statements
408 if (tokens.size() > 2 and tokens[1] == "BFC") 408 if (tokens.size() > 2 and tokens[1] == "BFC")
409 { 409 {
410 for_enum (BfcStatement, i) 410 for_enum(BfcStatement, i)
411 { 411 {
412 if (commentTextSimplified == format ("BFC %1", LDBfc::statementToString (i))) 412 if (commentTextSimplified == format("BFC %1", LDBfc::statementToString(i)))
413 return LDSpawn<LDBfc> (i); 413 return LDSpawn<LDBfc>(i);
414 } 414 }
415 415
416 // MLCAD is notorious for stuffing these statements in parts it 416 // MLCAD is notorious for stuffing these statements in parts it
417 // creates. The above block only handles valid statements, so we 417 // creates. The above block only handles valid statements, so we
418 // need to handle MLCAD-style invertnext, clip and noclip separately. 418 // need to handle MLCAD-style invertnext, clip and noclip separately.
419 if (commentTextSimplified == "BFC CERTIFY INVERTNEXT") 419 if (commentTextSimplified == "BFC CERTIFY INVERTNEXT")
420 return LDSpawn<LDBfc> (BfcStatement::InvertNext); 420 return LDSpawn<LDBfc>(BfcStatement::InvertNext);
421 else if (commentTextSimplified == "BFC CERTIFY CLIP") 421 else if (commentTextSimplified == "BFC CERTIFY CLIP")
422 return LDSpawn<LDBfc> (BfcStatement::Clip); 422 return LDSpawn<LDBfc>(BfcStatement::Clip);
423 else if (commentTextSimplified == "BFC CERTIFY NOCLIP") 423 else if (commentTextSimplified == "BFC CERTIFY NOCLIP")
424 return LDSpawn<LDBfc> (BfcStatement::NoClip); 424 return LDSpawn<LDBfc>(BfcStatement::NoClip);
425 } 425 }
426 426
427 if (tokens.size() > 2 and tokens[1] == "!LDFORGE") 427 if (tokens.size() > 2 and tokens[1] == "!LDFORGE")
428 { 428 {
429 // Handle LDForge-specific types, they're embedded into comments too 429 // Handle LDForge-specific types, they're embedded into comments too
430 if (tokens[2] == "OVERLAY") 430 if (tokens[2] == "OVERLAY")
431 { 431 {
432 CheckTokenCount (tokens, 9); 432 CheckTokenCount(tokens, 9);
433 CheckTokenNumbers (tokens, 5, 8); 433 CheckTokenNumbers(tokens, 5, 8);
434 434
435 LDOverlay* obj = LDSpawn<LDOverlay>(); 435 LDOverlay* obj = LDSpawn<LDOverlay>();
436 obj->setFileName (tokens[3]); 436 obj->setFileName(tokens[3]);
437 obj->setCamera (tokens[4].toLong()); 437 obj->setCamera(tokens[4].toLong());
438 obj->setX (tokens[5].toLong()); 438 obj->setX(tokens[5].toLong());
439 obj->setY (tokens[6].toLong()); 439 obj->setY(tokens[6].toLong());
440 obj->setWidth (tokens[7].toLong()); 440 obj->setWidth(tokens[7].toLong());
441 obj->setHeight (tokens[8].toLong()); 441 obj->setHeight(tokens[8].toLong());
442 return obj; 442 return obj;
443 } 443 }
444 else if (tokens[2] == "BEZIER_CURVE") 444 else if (tokens[2] == "BEZIER_CURVE")
445 { 445 {
446 CheckTokenCount (tokens, 16); 446 CheckTokenCount(tokens, 16);
447 CheckTokenNumbers (tokens, 3, 15); 447 CheckTokenNumbers(tokens, 3, 15);
448 LDBezierCurve* obj = LDSpawn<LDBezierCurve>(); 448 LDBezierCurve* obj = LDSpawn<LDBezierCurve>();
449 obj->setColor (StringToNumber (tokens[3])); 449 obj->setColor(StringToNumber(tokens[3]));
450 450
451 for (int i = 0; i < 4; ++i) 451 for (int i = 0; i < 4; ++i)
452 obj->setVertex (i, ParseVertex (tokens, 4 + (i * 3))); 452 obj->setVertex(i, ParseVertex(tokens, 4 +(i * 3)));
453 453
454 return obj; 454 return obj;
455 } 455 }
456 } 456 }
457 457
458 // Just a regular comment: 458 // Just a regular comment:
459 LDComment* obj = LDSpawn<LDComment>(); 459 LDComment* obj = LDSpawn<LDComment>();
460 obj->setText (commentText); 460 obj->setText(commentText);
461 return obj; 461 return obj;
462 } 462 }
463 463
464 case 1: 464 case 1:
465 { 465 {
466 // Subfile 466 // Subfile
467 CheckTokenCount (tokens, 15); 467 CheckTokenCount(tokens, 15);
468 CheckTokenNumbers (tokens, 1, 13); 468 CheckTokenNumbers(tokens, 1, 13);
469 LDDocument* document = g_win->documents()->getDocumentByName (tokens[14]); 469 LDDocument* document = g_win->documents()->getDocumentByName(tokens[14]);
470 470
471 // If we cannot open the file, mark it an error. Note we cannot use LDParseError 471 // If we cannot open the file, mark it an error. Note we cannot use LDParseError
472 // here because the error object needs the document reference. 472 // here because the error object needs the document reference.
473 if (not document) 473 if (not document)
474 { 474 {
475 LDError* obj = LDSpawn<LDError> (line, format ("Could not open %1", tokens[14])); 475 LDError* obj = LDSpawn<LDError>(line, format("Could not open %1", tokens[14]));
476 obj->setFileReferenced (tokens[14]); 476 obj->setFileReferenced(tokens[14]);
477 return obj; 477 return obj;
478 } 478 }
479 479
480 LDSubfileReference* obj = LDSpawn<LDSubfileReference>(); 480 LDSubfileReference* obj = LDSpawn<LDSubfileReference>();
481 obj->setColor (StringToNumber (tokens[1])); 481 obj->setColor(StringToNumber(tokens[1]));
482 obj->setPosition (ParseVertex (tokens, 2)); // 2 - 4 482 obj->setPosition(ParseVertex(tokens, 2)); // 2 - 4
483 483
484 Matrix transform; 484 Matrix transform;
485 485
486 for (int i = 0; i < 9; ++i) 486 for (int i = 0; i < 9; ++i)
487 transform[i] = tokens[i + 5].toDouble(); // 5 - 13 487 transform[i] = tokens[i + 5].toDouble(); // 5 - 13
488 488
489 obj->setTransform (transform); 489 obj->setTransform(transform);
490 obj->setFileInfo (document); 490 obj->setFileInfo(document);
491 return obj; 491 return obj;
492 } 492 }
493 493
494 case 2: 494 case 2:
495 { 495 {
496 CheckTokenCount (tokens, 8); 496 CheckTokenCount(tokens, 8);
497 CheckTokenNumbers (tokens, 1, 7); 497 CheckTokenNumbers(tokens, 1, 7);
498 498
499 // Line 499 // Line
500 LDLine* obj (LDSpawn<LDLine>()); 500 LDLine* obj(LDSpawn<LDLine>());
501 obj->setColor (StringToNumber (tokens[1])); 501 obj->setColor(StringToNumber(tokens[1]));
502 502
503 for (int i = 0; i < 2; ++i) 503 for (int i = 0; i < 2; ++i)
504 obj->setVertex (i, ParseVertex (tokens, 2 + (i * 3))); // 2 - 7 504 obj->setVertex(i, ParseVertex(tokens, 2 +(i * 3))); // 2 - 7
505 505
506 return obj; 506 return obj;
507 } 507 }
508 508
509 case 3: 509 case 3:
510 { 510 {
511 CheckTokenCount (tokens, 11); 511 CheckTokenCount(tokens, 11);
512 CheckTokenNumbers (tokens, 1, 10); 512 CheckTokenNumbers(tokens, 1, 10);
513 513
514 // Triangle 514 // Triangle
515 LDTriangle* obj (LDSpawn<LDTriangle>()); 515 LDTriangle* obj(LDSpawn<LDTriangle>());
516 obj->setColor (StringToNumber (tokens[1])); 516 obj->setColor(StringToNumber(tokens[1]));
517 517
518 for (int i = 0; i < 3; ++i) 518 for (int i = 0; i < 3; ++i)
519 obj->setVertex (i, ParseVertex (tokens, 2 + (i * 3))); // 2 - 10 519 obj->setVertex(i, ParseVertex(tokens, 2 +(i * 3))); // 2 - 10
520 520
521 return obj; 521 return obj;
522 } 522 }
523 523
524 case 4: 524 case 4:
525 case 5: 525 case 5:
526 { 526 {
527 CheckTokenCount (tokens, 14); 527 CheckTokenCount(tokens, 14);
528 CheckTokenNumbers (tokens, 1, 13); 528 CheckTokenNumbers(tokens, 1, 13);
529 529
530 // Quadrilateral / Conditional line 530 // Quadrilateral / Conditional line
531 LDObject* obj; 531 LDObject* obj;
532 532
533 if (num == 4) 533 if (num == 4)
534 obj = LDSpawn<LDQuad>(); 534 obj = LDSpawn<LDQuad>();
535 else 535 else
536 obj = LDSpawn<LDCondLine>(); 536 obj = LDSpawn<LDCondLine>();
537 537
538 obj->setColor (StringToNumber (tokens[1])); 538 obj->setColor(StringToNumber(tokens[1]));
539 539
540 for (int i = 0; i < 4; ++i) 540 for (int i = 0; i < 4; ++i)
541 obj->setVertex (i, ParseVertex (tokens, 2 + (i * 3))); // 2 - 13 541 obj->setVertex(i, ParseVertex(tokens, 2 +(i * 3))); // 2 - 13
542 542
543 return obj; 543 return obj;
544 } 544 }
545 545
546 default: 546 default:
547 throw QString ("Unknown line code number"); 547 throw QString("Unknown line code number");
548 } 548 }
549 } 549 }
550 catch (QString& e) 550 catch(QString& e)
551 { 551 {
552 // Strange line we couldn't parse 552 // Strange line we couldn't parse
553 return LDSpawn<LDError> (line, e); 553 return LDSpawn<LDError>(line, e);
554 } 554 }
555 } 555 }
556 556
557 // ============================================================================= 557 // =============================================================================
558 // 558 //
559 void LDDocument::reloadAllSubfiles() 559 void LDDocument::reloadAllSubfiles()
560 { 560 {
561 print ("Reloading subfiles of %1", getDisplayName()); 561 print("Reloading subfiles of %1", getDisplayName());
562 562
563 // Go through all objects in the current file and reload the subfiles 563 // Go through all objects in the current file and reload the subfiles
564 for (LDObject* obj : objects()) 564 for (LDObject* obj : objects())
565 { 565 {
566 if (obj->type() == OBJ_SubfileReference) 566 if (obj->type() == OBJ_SubfileReference)
567 { 567 {
568 LDSubfileReference* ref = static_cast<LDSubfileReference*> (obj); 568 LDSubfileReference* ref = static_cast<LDSubfileReference*>(obj);
569 LDDocument* fileInfo = m_documents->getDocumentByName (ref->fileInfo()->name()); 569 LDDocument* fileInfo = m_documents->getDocumentByName(ref->fileInfo()->name());
570 570
571 if (fileInfo) 571 if (fileInfo)
572 { 572 {
573 ref->setFileInfo (fileInfo); 573 ref->setFileInfo(fileInfo);
574 } 574 }
575 else 575 else
576 { 576 {
577 ref->replace (LDSpawn<LDError> (ref->asText(), 577 ref->replace(LDSpawn<LDError>(ref->asText(),
578 format ("Could not open %1", ref->fileInfo()->name()))); 578 format("Could not open %1", ref->fileInfo()->name())));
579 } 579 }
580 } 580 }
581 581
582 // Reparse gibberish files. It could be that they are invalid because 582 // Reparse gibberish files. It could be that they are invalid because
583 // of loading errors. Circumstances may be different now. 583 // of loading errors. Circumstances may be different now.
584 if (obj->type() == OBJ_Error) 584 if (obj->type() == OBJ_Error)
585 obj->replace (ParseLine (static_cast<LDError*> (obj)->contents())); 585 obj->replace(ParseLine(static_cast<LDError*>(obj)->contents()));
586 } 586 }
587 587
588 m_needsReCache = true; 588 m_needsReCache = true;
589 589
590 if (this == m_window->currentDocument()) 590 if (this == m_window->currentDocument())
591 m_window->buildObjectList(); 591 m_window->buildObjectList();
592 } 592 }
593 593
594 // ============================================================================= 594 // =============================================================================
595 // 595 //
596 int LDDocument::addObject (LDObject* obj) 596 int LDDocument::addObject(LDObject* obj)
597 { 597 {
598 history()->add (new AddHistoryEntry (objects().size(), obj)); 598 history()->add(new AddHistoryEntry(objects().size(), obj));
599 m_objects << obj; 599 m_objects << obj;
600 addKnownVertices (obj); 600 addKnownVertices(obj);
601 obj->setDocument (this); 601 obj->setDocument(this);
602 m_window->renderer()->compileObject (obj); 602 m_window->renderer()->compileObject(obj);
603 return getObjectCount() - 1; 603 return getObjectCount() - 1;
604 } 604 }
605 605
606 // ============================================================================= 606 // =============================================================================
607 // 607 //
608 void LDDocument::addObjects (const LDObjectList& objs) 608 void LDDocument::addObjects(const LDObjectList& objs)
609 { 609 {
610 for (LDObject* obj : objs) 610 for (LDObject* obj : objs)
611 { 611 {
612 if (obj) 612 if (obj)
613 addObject (obj); 613 addObject(obj);
614 } 614 }
615 } 615 }
616 616
617 // ============================================================================= 617 // =============================================================================
618 // 618 //
619 void LDDocument::insertObj (int pos, LDObject* obj) 619 void LDDocument::insertObj(int pos, LDObject* obj)
620 { 620 {
621 history()->add (new AddHistoryEntry (pos, obj)); 621 history()->add(new AddHistoryEntry(pos, obj));
622 m_objects.insert (pos, obj); 622 m_objects.insert(pos, obj);
623 obj->setDocument (this); 623 obj->setDocument(this);
624 m_window->renderer()->compileObject (obj); 624 m_window->renderer()->compileObject(obj);
625 625
626 626
627 #ifdef DEBUG 627 #ifdef DEBUG
628 if (not isCache()) 628 if (not isCache())
629 dprint ("Inserted object #%1 (%2) at %3\n", obj->id(), obj->typeName(), pos); 629 dprint("Inserted object #%1(%2) at %3\n", obj->id(), obj->typeName(), pos);
630 #endif 630 #endif
631 } 631 }
632 632
633 // ============================================================================= 633 // =============================================================================
634 // 634 //
635 void LDDocument::addKnownVertices (LDObject* obj) 635 void LDDocument::addKnownVertices(LDObject* obj)
636 { 636 {
637 auto it = m_objectVertices.find (obj); 637 auto it = m_objectVertices.find(obj);
638 638
639 if (it == m_objectVertices.end()) 639 if (it == m_objectVertices.end())
640 it = m_objectVertices.insert (obj, QVector<Vertex>()); 640 it = m_objectVertices.insert(obj, QVector<Vertex>());
641 else 641 else
642 it->clear(); 642 it->clear();
643 643
644 obj->getVertices (*it); 644 obj->getVertices(*it);
645 needVertexMerge(); 645 needVertexMerge();
646 } 646 }
647 647
648 // ============================================================================= 648 // =============================================================================
649 // 649 //
650 void LDDocument::forgetObject (LDObject* obj) 650 void LDDocument::forgetObject(LDObject* obj)
651 { 651 {
652 int idx = obj->lineNumber(); 652 int idx = obj->lineNumber();
653 653
654 if (m_objects[idx] == obj) 654 if (m_objects[idx] == obj)
655 { 655 {
656 obj->deselect(); 656 obj->deselect();
657 657
658 if (not isCache() and not m_beingDestroyed) 658 if (not isCache() and not m_beingDestroyed)
659 { 659 {
660 history()->add (new DelHistoryEntry (idx, obj)); 660 history()->add(new DelHistoryEntry(idx, obj));
661 m_objectVertices.remove (obj); 661 m_objectVertices.remove(obj);
662 } 662 }
663 663
664 m_objects.removeAt (idx); 664 m_objects.removeAt(idx);
665 obj->setDocument (nullptr); 665 obj->setDocument(nullptr);
666 } 666 }
667 } 667 }
668 668
669 // ============================================================================= 669 // =============================================================================
670 // 670 //
671 void LDDocument::setObject (int idx, LDObject* obj) 671 void LDDocument::setObject(int idx, LDObject* obj)
672 { 672 {
673 if (idx < 0 or idx >= m_objects.size()) 673 if (idx < 0 or idx >= m_objects.size())
674 return; 674 return;
675 675
676 // Mark this change to history 676 // Mark this change to history
677 if (not m_history->isIgnoring()) 677 if (not m_history->isIgnoring())
678 { 678 {
679 QString oldcode = getObject (idx)->asText(); 679 QString oldcode = getObject(idx)->asText();
680 QString newcode = obj->asText(); 680 QString newcode = obj->asText();
681 m_history->add (new EditHistoryEntry (idx, oldcode, newcode)); 681 m_history->add(new EditHistoryEntry(idx, oldcode, newcode));
682 } 682 }
683 683
684 m_objectVertices.remove (m_objects[idx]); 684 m_objectVertices.remove(m_objects[idx]);
685 m_objects[idx]->deselect(); 685 m_objects[idx]->deselect();
686 m_objects[idx]->setDocument (nullptr); 686 m_objects[idx]->setDocument(nullptr);
687 obj->setDocument (this); 687 obj->setDocument(this);
688 addKnownVertices (obj); 688 addKnownVertices(obj);
689 m_window->renderer()->compileObject (obj); 689 m_window->renderer()->compileObject(obj);
690 m_objects[idx] = obj; 690 m_objects[idx] = obj;
691 needVertexMerge(); 691 needVertexMerge();
692 } 692 }
693 693
694 // ============================================================================= 694 // =============================================================================
695 // 695 //
696 LDObject* LDDocument::getObject (int pos) const 696 LDObject* LDDocument::getObject(int pos) const
697 { 697 {
698 if (pos < m_objects.size()) 698 if (pos < m_objects.size())
699 return m_objects[pos]; 699 return m_objects[pos];
700 else 700 else
701 return nullptr; 701 return nullptr;
723 return name(); 723 return name();
724 724
725 if (not defaultName().isEmpty()) 725 if (not defaultName().isEmpty())
726 return "[" + defaultName() + "]"; 726 return "[" + defaultName() + "]";
727 727
728 return QObject::tr ("untitled"); 728 return QObject::tr("untitled");
729 } 729 }
730 730
731 // ============================================================================= 731 // =============================================================================
732 // 732 //
733 void LDDocument::initializeCachedData() 733 void LDDocument::initializeCachedData()
734 { 734 {
735 if (m_needsReCache) 735 if (m_needsReCache)
736 { 736 {
737 m_vertices.clear(); 737 m_vertices.clear();
738 738
739 for (LDObject* obj : inlineContents (true, true)) 739 for (LDObject* obj : inlineContents(true, true))
740 { 740 {
741 if (obj->type() == OBJ_SubfileReference) 741 if (obj->type() == OBJ_SubfileReference)
742 { 742 {
743 print ("Warning: unable to inline %1 into %2", 743 print("Warning: unable to inline %1 into %2",
744 static_cast<LDSubfileReference*> (obj)->fileInfo()->getDisplayName(), 744 static_cast<LDSubfileReference*>(obj)->fileInfo()->getDisplayName(),
745 getDisplayName()); 745 getDisplayName());
746 continue; 746 continue;
747 } 747 }
748 748
749 LDPolygon* data = obj->getPolygon(); 749 LDPolygon* data = obj->getPolygon();
760 760
761 if (m_verticesOutdated) 761 if (m_verticesOutdated)
762 { 762 {
763 m_objectVertices.clear(); 763 m_objectVertices.clear();
764 764
765 for (LDObject* obj : inlineContents (true, false)) 765 for (LDObject* obj : inlineContents(true, false))
766 addKnownVertices (obj); 766 addKnownVertices(obj);
767 767
768 mergeVertices(); 768 mergeVertices();
769 m_verticesOutdated = false; 769 m_verticesOutdated = false;
770 } 770 }
771 771
780 m_vertices.clear(); 780 m_vertices.clear();
781 781
782 for (QVector<Vertex> const& verts : m_objectVertices) 782 for (QVector<Vertex> const& verts : m_objectVertices)
783 m_vertices << verts; 783 m_vertices << verts;
784 784
785 removeDuplicates (m_vertices); 785 removeDuplicates(m_vertices);
786 m_needVertexMerge = false; 786 m_needVertexMerge = false;
787 } 787 }
788 788
789 // ============================================================================= 789 // =============================================================================
790 // 790 //
794 return polygonData(); 794 return polygonData();
795 } 795 }
796 796
797 // ============================================================================= 797 // =============================================================================
798 // ----------------------------------------------------------------------------- 798 // -----------------------------------------------------------------------------
799 LDObjectList LDDocument::inlineContents (bool deep, bool renderinline) 799 LDObjectList LDDocument::inlineContents(bool deep, bool renderinline)
800 { 800 {
801 LDObjectList objs; 801 LDObjectList objs;
802 802
803 if (m_manager->preInline (this, objs, deep, renderinline)) 803 if (m_manager->preInline(this, objs, deep, renderinline))
804 return objs; // Manager dealt with this inline 804 return objs; // Manager dealt with this inline
805 805
806 for (LDObject* obj : objects()) 806 for (LDObject* obj : objects())
807 { 807 {
808 // Skip those without scemantic meaning 808 // Skip those without scemantic meaning
811 811
812 // Got another sub-file reference, inline it if we're deep-inlining. If not, 812 // Got another sub-file reference, inline it if we're deep-inlining. If not,
813 // just add it into the objects normally. Yay, recursion! 813 // just add it into the objects normally. Yay, recursion!
814 if (deep == true and obj->type() == OBJ_SubfileReference) 814 if (deep == true and obj->type() == OBJ_SubfileReference)
815 { 815 {
816 for (LDObject* otherobj : static_cast<LDSubfileReference*> (obj)->inlineContents (deep, renderinline)) 816 for (LDObject* otherobj : static_cast<LDSubfileReference*>(obj)->inlineContents(deep, renderinline))
817 objs << otherobj; 817 objs << otherobj;
818 } 818 }
819 else 819 else
820 objs << obj->createCopy(); 820 objs << obj->createCopy();
821 } 821 }
823 return objs; 823 return objs;
824 } 824 }
825 825
826 // ============================================================================= 826 // =============================================================================
827 // 827 //
828 void LDDocument::addToSelection (LDObject* obj) // [protected] 828 void LDDocument::addToSelection(LDObject* obj) // [protected]
829 { 829 {
830 if (obj->isSelected() and obj->document() == this) 830 if (obj->isSelected() and obj->document() == this)
831 { 831 {
832 m_sel << obj; 832 m_sel << obj;
833 m_window->renderer()->compileObject (obj); 833 m_window->renderer()->compileObject(obj);
834 } 834 }
835 } 835 }
836 836
837 // ============================================================================= 837 // =============================================================================
838 // 838 //
839 void LDDocument::removeFromSelection (LDObject* obj) // [protected] 839 void LDDocument::removeFromSelection(LDObject* obj) // [protected]
840 { 840 {
841 if (not obj->isSelected() and obj->document() == this) 841 if (not obj->isSelected() and obj->document() == this)
842 { 842 {
843 m_sel.removeOne (obj); 843 m_sel.removeOne(obj);
844 m_window->renderer()->compileObject (obj); 844 m_window->renderer()->compileObject(obj);
845 } 845 }
846 } 846 }
847 847
848 // ============================================================================= 848 // =============================================================================
849 // 849 //
850 void LDDocument::clearSelection() 850 void LDDocument::clearSelection()
851 { 851 {
852 for (LDObject* obj : m_sel) 852 for (LDObject* obj : m_sel)
853 { 853 {
854 obj->deselect(); 854 obj->deselect();
855 m_window->renderer()->compileObject (obj); 855 m_window->renderer()->compileObject(obj);
856 } 856 }
857 857
858 m_sel.clear(); 858 m_sel.clear();
859 } 859 }
860 860
865 return m_sel; 865 return m_sel;
866 } 866 }
867 867
868 // ============================================================================= 868 // =============================================================================
869 // 869 //
870 void LDDocument::swapObjects (LDObject* one, LDObject* other) 870 void LDDocument::swapObjects(LDObject* one, LDObject* other)
871 { 871 {
872 int a = m_objects.indexOf (one); 872 int a = m_objects.indexOf(one);
873 int b = m_objects.indexOf (other); 873 int b = m_objects.indexOf(other);
874 874
875 if (a != b and a != -1 and b != -1) 875 if (a != b and a != -1 and b != -1)
876 { 876 {
877 m_objects[b] = one; 877 m_objects[b] = one;
878 m_objects[a] = other; 878 m_objects[a] = other;
879 addToHistory (new SwapHistoryEntry (one->id(), other->id())); 879 addToHistory(new SwapHistoryEntry(one->id(), other->id()));
880 } 880 }
881 } 881 }
882 882
883 // ============================================================================= 883 // =============================================================================
884 // 884 //
885 QString LDDocument::shortenName (QString a) // [static] 885 QString LDDocument::shortenName(QString a) // [static]
886 { 886 {
887 QString shortname = Basename (a); 887 QString shortname = Basename(a);
888 QString topdirname = Basename (Dirname (a)); 888 QString topdirname = Basename(Dirname(a));
889 889
890 if (g_specialSubdirectories.contains (topdirname)) 890 if (g_specialSubdirectories.contains(topdirname))
891 shortname.prepend (topdirname + "\\"); 891 shortname.prepend(topdirname + "\\");
892 892
893 return shortname; 893 return shortname;
894 } 894 }
895 895
896 // ============================================================================= 896 // =============================================================================

mercurial