- initial overhaul with smart pointers

Fri, 09 May 2014 12:06:56 +0300

author
Santeri Piippo <crimsondusk64@gmail.com>
date
Fri, 09 May 2014 12:06:56 +0300
changeset 768
29e6c5552388
parent 767
44f0d5322628
child 769
8bb3bed44570

- initial overhaul with smart pointers

src/actions.cc file | annotate | diff | comparison | revisions
src/actionsEdit.cc file | annotate | diff | comparison | revisions
src/addObjectDialog.cc file | annotate | diff | comparison | revisions
src/addObjectDialog.h file | annotate | diff | comparison | revisions
src/basics.cc file | annotate | diff | comparison | revisions
src/basics.h file | annotate | diff | comparison | revisions
src/editHistory.cc file | annotate | diff | comparison | revisions
src/editHistory.h file | annotate | diff | comparison | revisions
src/extPrograms.cc file | annotate | diff | comparison | revisions
src/glCompiler.cc file | annotate | diff | comparison | revisions
src/glCompiler.h file | annotate | diff | comparison | revisions
src/glRenderer.cc file | annotate | diff | comparison | revisions
src/glRenderer.h file | annotate | diff | comparison | revisions
src/ldDocument.cc file | annotate | diff | comparison | revisions
src/ldDocument.h file | annotate | diff | comparison | revisions
src/ldObject.cc file | annotate | diff | comparison | revisions
src/ldObject.h file | annotate | diff | comparison | revisions
src/main.cc file | annotate | diff | comparison | revisions
src/mainWindow.cc file | annotate | diff | comparison | revisions
src/miscallenous.cc file | annotate | diff | comparison | revisions
src/partDownloader.cc file | annotate | diff | comparison | revisions
src/primitives.cc file | annotate | diff | comparison | revisions
--- a/src/actions.cc	Mon May 05 17:18:01 2014 +0300
+++ b/src/actions.cc	Fri May 09 12:06:56 2014 +0300
@@ -86,7 +86,7 @@
 
 	newFile();
 
-	const LDBFC::Statement BFCType =
+	const LDBFC::Statement bfctype =
 		ui.rb_bfc_ccw->isChecked() ? LDBFC::CertifyCCW :
 		ui.rb_bfc_cw->isChecked()  ? LDBFC::CertifyCW : LDBFC::NoCertify;
 
@@ -94,17 +94,20 @@
 		ui.rb_license_ca->isChecked()    ? g_CALicense :
 		ui.rb_license_nonca->isChecked() ? g_nonCALicense : "";
 
-	getCurrentDocument()->addObjects (
-	{
-		new LDComment (ui.le_title->text()),
-		new LDComment ("Name: <untitled>.dat"),
-		new LDComment (format ("Author: %1", ui.le_author->text())),
-		new LDComment (format ("!LDRAW_ORG Unofficial_Part")),
-		(license != "" ? new LDComment (license) : null),
-		new LDEmpty,
-		new LDBFC (BFCType),
-		new LDEmpty,
-	});
+	LDObjectList objs;
+	objs << spawn<LDComment> (ui.le_title->text());
+	objs << spawn<LDComment> ("Name: <untitled>.dat");
+	objs << spawn<LDComment> (format ("Author: %1", ui.le_author->text()));
+	objs << spawn<LDComment> (format ("!LDRAW_ORG Unofficial_Part"));
+
+	if (not license.isEmpty())
+		objs << spawn<LDComment> (license);
+
+	objs << spawn<LDEmpty>();
+	objs << spawn<LDBFC> (bfctype);
+	objs << spawn<LDEmpty>();
+
+	getCurrentDocument()->addObjects (objs);
 
 	doFullRefresh();
 }
@@ -122,7 +125,7 @@
 {
 	String name = QFileDialog::getOpenFileName (g_win, "Open File", "", "LDraw files (*.dat *.ldr)");
 
-	if (name.length() == 0)
+	if (name.isEmpty())
 		return;
 
 	openMainFile (name);
@@ -200,56 +203,56 @@
 //
 DEFINE_ACTION (NewSubfile, 0)
 {
-	AddObjectDialog::staticDialog (LDObject::ESubfile, null);
+	AddObjectDialog::staticDialog (LDObject::ESubfile, LDObjectPtr());
 }
 
 // =============================================================================
 //
 DEFINE_ACTION (NewLine, 0)
 {
-	AddObjectDialog::staticDialog (LDObject::ELine, null);
+	AddObjectDialog::staticDialog (LDObject::ELine, LDObjectPtr());
 }
 
 // =============================================================================
 //
 DEFINE_ACTION (NewTriangle, 0)
 {
-	AddObjectDialog::staticDialog (LDObject::ETriangle, null);
+	AddObjectDialog::staticDialog (LDObject::ETriangle, LDObjectPtr());
 }
 
 // =============================================================================
 //
 DEFINE_ACTION (NewQuad, 0)
 {
-	AddObjectDialog::staticDialog (LDObject::EQuad, null);
+	AddObjectDialog::staticDialog (LDObject::EQuad, LDObjectPtr());
 }
 
 // =============================================================================
 //
 DEFINE_ACTION (NewCLine, 0)
 {
-	AddObjectDialog::staticDialog (LDObject::ECondLine, null);
+	AddObjectDialog::staticDialog (LDObject::ECondLine, LDObjectPtr());
 }
 
 // =============================================================================
 //
 DEFINE_ACTION (NewComment, 0)
 {
-	AddObjectDialog::staticDialog (LDObject::EComment, null);
+	AddObjectDialog::staticDialog (LDObject::EComment, LDObjectPtr());
 }
 
 // =============================================================================
 //
 DEFINE_ACTION (NewBFC, 0)
 {
-	AddObjectDialog::staticDialog (LDObject::EBFC, null);
+	AddObjectDialog::staticDialog (LDObject::EBFC, LDObjectPtr());
 }
 
 // =============================================================================
 //
 DEFINE_ACTION (NewVertex, 0)
 {
-	AddObjectDialog::staticDialog (LDObject::EVertex, null);
+	AddObjectDialog::staticDialog (LDObject::EVertex, LDObjectPtr());
 }
 
 // =============================================================================
@@ -259,7 +262,7 @@
 	if (selection().size() != 1)
 		return;
 
-	LDObject* obj = selection() [0];
+	LDObjectPtr obj = selection() [0];
 	AddObjectDialog::staticDialog (obj->type(), obj);
 }
 
@@ -287,7 +290,7 @@
 //
 DEFINE_ACTION (SelectAll, CTRL (A))
 {
-	for (LDObject* obj : getCurrentDocument()->objects())
+	for (LDObjectPtr obj : getCurrentDocument()->objects())
 		obj->select();
 
 	ui->objectList->selectAll();
@@ -304,7 +307,7 @@
 
 	getCurrentDocument()->clearSelection();
 
-	for (LDObject* obj : getCurrentDocument()->objects())
+	for (LDObjectPtr obj : getCurrentDocument()->objects())
 		if (obj->color() == colnum)
 			obj->select();
 
@@ -329,21 +332,21 @@
 
 	if (type == LDObject::ESubfile)
 	{
-		refName = static_cast<LDSubfile*> (selection()[0])->fileInfo()->name();
+		refName = selection()[0].staticCast<LDSubfile>()->fileInfo()->name();
 
-		for (LDObject* obj : selection())
-			if (static_cast<LDSubfile*> (obj)->fileInfo()->name() != refName)
+		for (LDObjectPtr obj : selection())
+			if (obj.staticCast<LDSubfile>()->fileInfo()->name() != refName)
 				return;
 	}
 
 	getCurrentDocument()->clearSelection();
 
-	for (LDObject* obj : getCurrentDocument()->objects())
+	for (LDObjectPtr obj : getCurrentDocument()->objects())
 	{
 		if (obj->type() != type)
 			continue;
 
-		if (type == LDObject::ESubfile && static_cast<LDSubfile*> (obj)->fileInfo()->name() != refName)
+		if (type == LDObject::ESubfile && obj.staticCast<LDSubfile>()->fileInfo()->name() != refName)
 			continue;
 
 		obj->select();
@@ -402,7 +405,7 @@
 
 	getCurrentDocument()->clearSelection();
 
-	for (LDObject* obj : objs)
+	for (LDObjectPtr obj : objs)
 	{
 		getCurrentDocument()->insertObj (idx, obj);
 		obj->select();
@@ -435,7 +438,7 @@
 		return;
 	}
 
-	for (LDObject* obj : selection())
+	for (LDObjectPtr obj : selection())
 	{
 		String contents = obj->asText();
 		QByteArray data = contents.toUtf8();
@@ -469,7 +472,7 @@
 
 	for (String line : String (te_edit->toPlainText()).split ("\n"))
 	{
-		LDObject* obj = parseLine (line);
+		LDObjectPtr obj = parseLine (line);
 
 		getCurrentDocument()->insertObj (idx, obj);
 		obj->select();
@@ -519,7 +522,7 @@
 //
 DEFINE_ACTION (VisibilityToggle, 0)
 {
-	for (LDObject* obj : selection())
+	for (LDObjectPtr obj : selection())
 		obj->setHidden (not obj->isHidden());
 
 	refresh();
@@ -529,7 +532,7 @@
 //
 DEFINE_ACTION (VisibilityHide, 0)
 {
-	for (LDObject* obj : selection())
+	for (LDObjectPtr obj : selection())
 		obj->setHidden (true);
 
 	refresh();
@@ -539,7 +542,7 @@
 //
 DEFINE_ACTION (VisibilityReveal, 0)
 {
-	for (LDObject* obj : selection())
+	for (LDObjectPtr obj : selection())
 	obj->setHidden (false);
 	refresh();
 }
@@ -688,7 +691,7 @@
 {
 	bool ok;
 	int defval = 0;
-	LDObject* obj;
+	LDObjectPtr obj;
 
 	if (selection().size() == 1)
 		defval = selection()[0]->lineNumber();
@@ -723,7 +726,7 @@
 	String			subtitle;
 
 	// Comment containing the title of the parent document
-	LDComment*		titleobj = dynamic_cast<LDComment*> (getCurrentDocument()->getObject (0));
+	LDCommentPtr	titleobj = getCurrentDocument()->getObject (0).dynamicCast<LDComment>();
 
 	// License text for the subfile
 	String			license = getLicenseText (cfg::defaultLicense);
@@ -744,7 +747,7 @@
 		subtitle = "~subfile";
 
 	// Remove duplicate tildes
-	while (subtitle[0] == '~' && subtitle[1] == '~')
+	while (subtitle.startsWith ("~~"))
 		subtitle.remove (0, 1);
 
 	// If this the parent document isn't already in s/, we need to stuff it into
@@ -763,11 +766,14 @@
 			subdirname = desiredPath;
 			QDir().mkpath (subdirname);
 		}
+		else
+			return;
 	}
 
 	// Determine the body of the name of the subfile
 	if (not parentpath.isEmpty())
 	{
+		// Chop existing '.dat' suffix
 		if (parentpath.endsWith (".dat"))
 			parentpath.chop (4);
 
@@ -782,6 +788,8 @@
 		QFile f;
 		String testfname;
 
+		// Now find the appropriate filename. Increase the number of the subfile
+		// until we find a name which isn't already taken.
 		do
 		{
 			digits.setNum (subidx++);
@@ -796,14 +804,12 @@
 
 	// Determine the BFC winding type used in the main document - it is to
 	// be carried over to the subfile.
-	for (LDObject* obj : getCurrentDocument()->objects())
+	for (LDObjectPtr obj : getCurrentDocument()->objects())
 	{
-		LDBFC* bfc = dynamic_cast<LDBFC*> (obj);
-
-		if (not bfc)
+		if (obj->type() != LDObject::EBFC)
 			continue;
 
-		LDBFC::Statement a = bfc->statement();
+		LDBFC::Statement a = obj.staticCast<LDBFC>()->statement();
 
 		if (a == LDBFC::CertifyCCW || a == LDBFC::CertifyCW || a == LDBFC::NoCertify)
 		{
@@ -813,7 +819,7 @@
 	}
 
 	// Get the body of the document in LDraw code
-	for (LDObject* obj : selection())
+	for (LDObjectPtr obj : selection())
 		code << obj->asText();
 
 	// Create the new subfile document
@@ -821,38 +827,41 @@
 	doc->setImplicit (false);
 	doc->setFullPath (fullsubname);
 	doc->setName (LDDocument::shortenName (fullsubname));
-	doc->addObjects (
-	{
-		new LDComment (subtitle),
-		new LDComment ("Name: "),
-		new LDComment (format ("Author: %1 [%2]", cfg::defaultName, cfg::defaultUser)),
-		new LDComment (format ("!LDRAW_ORG Unofficial_Subpart")),
-		(license != "" ? new LDComment (license) : null),
-		new LDEmpty,
-		new LDBFC (bfctype),
-		new LDEmpty,
-	});
+
+	LDObjectList objs;
+	objs << spawn<LDComment> (subtitle);
+	objs << spawn<LDComment> ("Name: "); // This gets filled in when the subfile is saved
+	objs << spawn<LDComment> (format ("Author: %1 [%2]", cfg::defaultName, cfg::defaultUser));
+	objs << spawn<LDComment> ("!LDRAW_ORG Unofficial_Subpart");
+
+	if (not license.isEmpty())
+		objs << spawn<LDComment> (license);
+
+	objs << spawn<LDEmpty>();
+	objs << spawn<LDBFC> (bfctype);
+	objs << spawn<LDEmpty>();
+
+	doc->addObjects (objs);
 
 	// Add the actual subfile code to the new document
 	for (String line : code)
 	{
-		LDObject* obj = parseLine (line);
+		LDObjectPtr obj = parseLine (line);
 		doc->addObject (obj);
 	}
 
 	// Try save it
 	if (save (doc, true))
 	{
-		// Remove the selection now
-		for (LDObject* obj : selection())
+		// Save was successful. Delete the original selection now from the
+		// main document.
+		for (LDObjectPtr obj : selection())
 			obj->destroy();
 
-		// Compile all objects in the new subfile
-		R()->compiler()->compileDocument (doc);
 		g_loadedFiles << doc;
 
 		// Add a reference to the new subfile to where the selection was
-		LDSubfile* ref = new LDSubfile();
+		LDSubfilePtr ref (spawn<LDSubfile>());
 		ref->setColor (maincolor);
 		ref->setFileInfo (doc);
 		ref->setPosition (g_origin);
--- a/src/actionsEdit.cc	Mon May 05 17:18:01 2014 +0300
+++ b/src/actionsEdit.cc	Fri May 09 12:06:56 2014 +0300
@@ -49,7 +49,7 @@
 	// Now, copy the contents into the clipboard.
 	String data;
 
-	for (LDObject* obj : objs)
+	for (LDObjectPtr obj : objs)
 	{
 		if (data.length() > 0)
 			data += "\n";
@@ -90,7 +90,7 @@
 
 	for (String line : clipboardText.split ("\n"))
 	{
-		LDObject* pasted = parseLine (line);
+		LDObjectPtr pasted = parseLine (line);
 		getCurrentDocument()->insertObj (idx++, pasted);
 		pasted->select();
 		++num;
@@ -115,7 +115,7 @@
 {
 	LDObjectList sel = selection();
 
-	for (LDObject* obj : sel)
+	for (LDObjectPtr obj : sel)
 	{
 		// Get the index of the subfile so we know where to insert the
 		// inlined contents.
@@ -124,14 +124,14 @@
 		if (idx == -1 || obj->type() != LDObject::ESubfile)
 			continue;
 
-		LDObjectList objs = static_cast<LDSubfile*> (obj)->inlineContents (deep, false);
+		LDObjectList objs = obj.staticCast<LDSubfile>()->inlineContents (deep, false);
 
 		// Merge in the inlined objects
-		for (LDObject* inlineobj : objs)
+		for (LDObjectPtr inlineobj : objs)
 		{
 			String line = inlineobj->asText();
 			inlineobj->destroy();
-			LDObject* newobj = parseLine (line);
+			LDObjectPtr newobj = parseLine (line);
 			getCurrentDocument()->insertObj (idx++, newobj);
 			newobj->select();
 		}
@@ -160,7 +160,7 @@
 	LDObjectList objs = selection();
 	int num = 0;
 
-	for (LDObject* obj : objs)
+	for (LDObjectPtr obj : objs)
 	{
 		if (obj->type() != LDObject::EQuad)
 			continue;
@@ -171,7 +171,7 @@
 		if (index == -1)
 			return;
 
-		QList<LDTriangle*> triangles = static_cast<LDQuad*> (obj)->splitToTriangles();
+		QList<LDTrianglePtr> triangles = obj.staticCast<LDQuad>()->splitToTriangles();
 
 		// Replace the quad with the first triangle and add the second triangle
 		// after the first one.
@@ -192,7 +192,7 @@
 	if (selection().size() != 1)
 		return;
 
-	LDObject* obj = selection()[0];
+	LDObjectPtr obj = selection()[0];
 	QDialog* dlg = new QDialog;
 	Ui::EditRawUI ui;
 
@@ -200,7 +200,7 @@
 	ui.code->setText (obj->asText());
 
 	if (obj->type() == LDObject::EError)
-		ui.errorDescription->setText (static_cast<LDError*> (obj)->reason());
+		ui.errorDescription->setText (obj.staticCast<LDError>()->reason());
 	else
 	{
 		ui.errorDescription->hide();
@@ -211,7 +211,7 @@
 		return;
 
 	// Reinterpret it from the text of the input field
-	LDObject* newobj = parseLine (ui.code->text());
+	LDObjectPtr newobj = parseLine (ui.code->text());
 	obj->replace (newobj);
 	refresh();
 }
@@ -235,7 +235,7 @@
 	// Show the dialog to the user now and ask for a color.
 	if (ColorSelector::selectColor (colnum, defcol, g_win))
 	{
-		for (LDObject* obj : objs)
+		for (LDObjectPtr obj : objs)
 		{
 			if (not obj->isColored())
 				continue;
@@ -254,44 +254,41 @@
 	LDObjectList objs = selection();
 	int num = 0;
 
-	for (LDObject* obj : objs)
+	for (LDObjectPtr obj : objs)
 	{
 		const LDObject::Type type = obj->type();
 		if (type != LDObject::EQuad && type != LDObject::ETriangle)
 			continue;
 
-		int numLines;
-		LDLine* lines[4];
+		LDLinePtr lines[4];
 
 		if (type == LDObject::EQuad)
 		{
-			numLines = 4;
-
-			LDQuad* quad = static_cast<LDQuad*> (obj);
-			lines[0] = new LDLine (quad->vertex (0), quad->vertex (1));
-			lines[1] = new LDLine (quad->vertex (1), quad->vertex (2));
-			lines[2] = new LDLine (quad->vertex (2), quad->vertex (3));
-			lines[3] = new LDLine (quad->vertex (3), quad->vertex (0));
+			LDQuadPtr quad = obj.staticCast<LDQuad>();
+			lines[0] = spawn<LDLine> (quad->vertex (0), quad->vertex (1));
+			lines[1] = spawn<LDLine> (quad->vertex (1), quad->vertex (2));
+			lines[2] = spawn<LDLine> (quad->vertex (2), quad->vertex (3));
+			lines[3] = spawn<LDLine> (quad->vertex (3), quad->vertex (0));
 		}
 		else
 		{
-			numLines = 3;
-
-			LDTriangle* tri = static_cast<LDTriangle*> (obj);
-			lines[0] = new LDLine (tri->vertex (0), tri->vertex (1));
-			lines[1] = new LDLine (tri->vertex (1), tri->vertex (2));
-			lines[2] = new LDLine (tri->vertex (2), tri->vertex (0));
+			LDTrianglePtr tri = obj.staticCast<LDTriangle>();
+			lines[0] = spawn<LDLine> (tri->vertex (0), tri->vertex (1));
+			lines[1] = spawn<LDLine> (tri->vertex (1), tri->vertex (2));
+			lines[2] = spawn<LDLine> (tri->vertex (2), tri->vertex (0));
 		}
 
-		for (int i = 0; i < numLines; ++i)
+		for (int i = 0; i < countof (lines); ++i)
 		{
+			if (lines[i] == null)
+				continue;
+
 			long idx = obj->lineNumber() + i + 1;
-
 			lines[i]->setColor (edgecolor);
 			getCurrentDocument()->insertObj (idx, lines[i]);
 		}
 
-		num += numLines;
+		num += countof (lines);
 	}
 
 	print (tr ("Added %1 border lines"), num);
@@ -304,7 +301,7 @@
 {
 	int num = 0;
 
-	for (LDObject* obj : selection())
+	for (LDObjectPtr obj : selection())
 	{
 		if (obj->numVertices() < 2)
 			continue;
@@ -313,7 +310,7 @@
 
 		for (int i = 0; i < obj->numVertices(); ++i)
 		{
-			LDVertex* vert = new LDVertex;
+			QSharedPointer<LDVertex> vert (spawn<LDVertex>());
 			vert->pos = obj->vertex (i);
 			vert->setColor (obj->color());
 			getCurrentDocument()->insertObj (++ln, vert);
@@ -365,7 +362,7 @@
 	// Apply the grid values
 	vect *= *currentGrid().coordsnap;
 
-	for (LDObject* obj : selection())
+	for (LDObjectPtr obj : selection())
 		obj->move (vect);
 
 	g_win->refresh();
@@ -409,7 +406,7 @@
 {
 	LDObjectList sel = selection();
 
-	for (LDObject* obj : sel)
+	for (LDObjectPtr obj : sel)
 		obj->invert();
 
 	refresh();
@@ -452,7 +449,7 @@
 	});
 
 	// Apply the above matrix to everything
-	for (LDObject* obj : sel)
+	for (LDObjectPtr obj : sel)
 	{
 		if (obj->numVertices())
 		{
@@ -465,7 +462,7 @@
 		}
 		elif (obj->hasMatrix())
 		{
-			LDMatrixObject* mo = dynamic_cast<LDMatrixObject*> (obj);
+			LDMatrixObjectPtr mo = obj.dynamicCast<LDMatrixObject>();
 
 			// Transform the position
 			Vertex v = mo->position();
@@ -477,7 +474,7 @@
 		}
 		elif (obj->type() == LDObject::EVertex)
 		{
-			LDVertex* vert = static_cast<LDVertex*> (obj);
+			LDVertexPtr vert = obj.staticCast<LDVertex>();
 			Vertex v = vert->pos;
 			rotateVertex (v, rotpoint, transform);
 			vert->pos = v;
@@ -526,9 +523,9 @@
 	setlocale (LC_ALL, "C");
 	int num = 0;
 
-	for (LDObject* obj : selection())
+	for (LDObjectPtr obj : selection())
 	{
-		LDMatrixObject* mo = dynamic_cast<LDMatrixObject*> (obj);
+		LDMatrixObjectPtr mo = obj.dynamicCast<LDMatrixObject>();
 
 		if (mo != null)
 		{
@@ -566,7 +563,7 @@
 {
 	int num = 0;
 
-	for (LDObject* obj : selection())
+	for (LDObjectPtr obj : selection())
 	{
 		if (not obj->isColored())
 			continue;
@@ -607,7 +604,7 @@
 	if (ui.y->isChecked()) sel << Y;
 	if (ui.z->isChecked()) sel << Z;
 
-	for (LDObject* obj : selection())
+	for (LDObjectPtr obj : selection())
 	{
 		for (int i = 0; i < obj->numVertices(); ++i)
 		{
@@ -653,7 +650,7 @@
 	if (ui.y->isChecked()) sel << Y;
 	if (ui.z->isChecked()) sel << Z;
 
-	for (LDObject* obj : selection())
+	for (LDObjectPtr obj : selection())
 	{
 		for (int i = 0; i < obj->numVertices(); ++i)
 		{
@@ -679,12 +676,12 @@
 	LDObjectList sel = selection();
 	int num = 0;
 
-	for (LDObject* obj : sel)
+	for (LDObjectPtr obj : sel)
 	{
 		if (obj->type() != LDObject::ECondLine)
 			continue;
 
-		static_cast<LDCondLine*> (obj)->demote();
+		obj.staticCast<LDCondLine>()->demote();
 		++num;
 	}
 
@@ -696,7 +693,7 @@
 //
 static bool isColorUsed (int colnum)
 {
-	for (LDObject* obj : getCurrentDocument()->objects())
+	for (LDObjectPtr obj : getCurrentDocument()->objects())
 		if (obj->isColored() && obj->color() == colnum)
 			return true;
 
@@ -718,7 +715,7 @@
 		return;
 	}
 
-	for (LDObject* obj : selection())
+	for (LDObjectPtr obj : selection())
 	{
 		if (not obj->isColored())
 			continue;
@@ -734,7 +731,7 @@
 //
 DEFINE_ACTION (AddHistoryLine, 0)
 {
-	LDObject* obj;
+	LDObjectPtr obj;
 	bool ishistory = false,
 		 prevIsHistory = false;
 
@@ -754,14 +751,14 @@
 		ui->m_username->text(),
 		ui->m_comment->text());
 
-	LDComment* comm = new LDComment (commentText);
+	LDCommentPtr comm (spawn<LDComment> (commentText));
 
 	// Find a spot to place the new comment
 	for (obj = getCurrentDocument()->getObject (0);
 		obj != null && obj->next() != null && not obj->next()->isScemantic();
 		obj = obj->next())
 	{
-		LDComment* comm = dynamic_cast<LDComment*> (obj);
+		LDCommentPtr comm = obj.dynamicCast<LDComment>();
 
 		if (comm != null && comm->text().startsWith ("!HISTORY "))
 			ishistory = true;
@@ -782,7 +779,7 @@
 	// If we're adding a history line right before a scemantic object, pad it
 	// an empty line
 	if (obj && obj->next() && obj->next()->isScemantic())
-		getCurrentDocument()->insertObj (idx, new LDEmpty);
+		getCurrentDocument()->insertObj (idx, LDEmptyPtr (spawn<LDEmpty>()));
 
 	buildObjList();
 	delete ui;
--- a/src/addObjectDialog.cc	Mon May 05 17:18:01 2014 +0300
+++ b/src/addObjectDialog.cc	Fri May 09 12:06:56 2014 +0300
@@ -53,7 +53,7 @@
 
 // =============================================================================
 //
-AddObjectDialog::AddObjectDialog (const LDObject::Type type, LDObject* obj, QWidget* parent) :
+AddObjectDialog::AddObjectDialog (const LDObject::Type type, LDObjectPtr obj, QWidget* parent) :
 	QDialog (parent)
 {
 	setlocale (LC_ALL, "C");
@@ -68,7 +68,7 @@
 			le_comment = new QLineEdit;
 
 			if (obj)
-				le_comment->setText (static_cast<LDComment*> (obj)->text());
+				le_comment->setText (obj.staticCast<LDComment>()->text());
 
 			le_comment->setMinimumWidth (384);
 		} break;
@@ -108,7 +108,7 @@
 			}
 
 			if (obj)
-				rb_bfcType->setValue ( (int) static_cast<LDBFC*> (obj)->statement());
+				rb_bfcType->setValue ((int) obj.staticCast<LDBFC>()->statement());
 		} break;
 
 		case LDObject::ESubfile:
@@ -131,7 +131,7 @@
 
 					// If this primitive is the one the current object points to,
 					// select it by default
-					if (obj && static_cast<LDSubfile*> (obj)->fileInfo()->name() == prim.name)
+					if (obj && obj.staticCast<LDSubfile>()->fileInfo()->name() == prim.name)
 						tw_subfileList->setCurrentItem (item);
 				}
 
@@ -145,7 +145,7 @@
 
 			if (obj)
 			{
-				LDSubfile* ref = static_cast<LDSubfile*> (obj);
+				LDSubfilePtr ref = obj.staticCast<LDSubfile>();
 				le_subfileName->setText (ref->fileInfo()->name());
 			}
 		} break;
@@ -157,7 +157,7 @@
 	}
 
 	QPixmap icon = getIcon (format ("add-%1", typeName));
-	LDObject* defaults = LDObject::getDefault (type);
+	LDObjectPtr defaults = LDObject::getDefault (type);
 
 	lb_typeIcon = new QLabel;
 	lb_typeIcon->setPixmap (icon);
@@ -225,8 +225,7 @@
 
 	if (defaults->hasMatrix())
 	{
-		LDMatrixObject* mo = dynamic_cast<LDMatrixObject*> (obj);
-
+		LDMatrixObjectPtr mo = obj.dynamicCast<LDMatrixObject>();
 		QLabel* lb_matrix = new QLabel ("Matrix:");
 		le_matrix = new QLineEdit;
 		// le_matrix->setValidator (new QDoubleValidator);
@@ -317,17 +316,17 @@
 // =============================================================================
 // =============================================================================
 template<typename T>
-static T* initObj (LDObject*& obj)
+static QSharedPointer<T> initObj (LDObjectPtr& obj)
 {
 	if (obj == null)
-		obj = new T;
+		obj = LDObjectPtr (new T);
 
-	return static_cast<T*> (obj);
+	return obj.staticCast<T>();
 }
 
 // =============================================================================
 // =============================================================================
-void AddObjectDialog::staticDialog (const LDObject::Type type, LDObject* obj)
+void AddObjectDialog::staticDialog (const LDObject::Type type, LDObjectPtr obj)
 {
 	setlocale (LC_ALL, "C");
 
@@ -367,7 +366,7 @@
 	{
 		case LDObject::EComment:
 		{
-			LDComment* comm = initObj<LDComment> (obj);
+			LDCommentPtr comm = initObj<LDComment> (obj);
 			comm->setText (dlg.le_comment->text());
 		}
 		break;
@@ -395,13 +394,13 @@
 
 		case LDObject::EBFC:
 		{
-			LDBFC* bfc = initObj<LDBFC> (obj);
+			LDBFCPtr bfc = initObj<LDBFC> (obj);
 			bfc->setStatement ((LDBFC::Statement) dlg.rb_bfcType->value());
 		} break;
 
 		case LDObject::EVertex:
 		{
-			LDVertex* vert = initObj<LDVertex> (obj);
+			LDVertexPtr vert = initObj<LDVertex> (obj);
 			vert->pos.apply ([&](Axis ax, double& value) { value = dlg.dsb_coords[ax]->value(); });
 		}
 		break;
@@ -421,7 +420,7 @@
 				return;
 			}
 
-			LDSubfile* ref = initObj<LDSubfile> (obj);
+			LDSubfilePtr ref = initObj<LDSubfile> (obj);
 			assert (ref);
 
 			for_axes (ax)
--- a/src/addObjectDialog.h	Mon May 05 17:18:01 2014 +0300
+++ b/src/addObjectDialog.h	Fri May 09 12:06:56 2014 +0300
@@ -34,8 +34,8 @@
 	Q_OBJECT
 
 	public:
-		AddObjectDialog (const LDObject::Type type, LDObject* obj, QWidget* parent = null);
-		static void staticDialog (const LDObject::Type type, LDObject* obj);
+		AddObjectDialog (const LDObject::Type type, LDObjectPtr obj, QWidget* parent = null);
+		static void staticDialog (const LDObject::Type type, LDObjectPtr obj);
 
 		QLabel* lb_typeIcon;
 
--- a/src/basics.cc	Mon May 05 17:18:01 2014 +0300
+++ b/src/basics.cc	Fri May 09 12:06:56 2014 +0300
@@ -225,13 +225,13 @@
 	if (not getCurrentDocument())
 		return;
 
-	for (LDObject* obj : getCurrentDocument()->objects())
+	for (LDObjectPtr obj : getCurrentDocument()->objects())
 		calcObject (obj);
 }
 
 // =============================================================================
 //
-void LDBoundingBox::calcObject (LDObject* obj)
+void LDBoundingBox::calcObject (LDObjectPtr obj)
 {
 	switch (obj->type())
 	{
@@ -246,10 +246,10 @@
 
 		case LDObject::ESubfile:
 		{
-			LDSubfile* ref = static_cast<LDSubfile*> (obj);
+			LDSubfilePtr ref = obj.staticCast<LDSubfile>();
 			LDObjectList objs = ref->inlineContents (true, false);
 
-			for (LDObject * obj : objs)
+			for (LDObjectPtr obj : objs)
 			{
 				calcObject (obj);
 				obj->destroy();
@@ -272,7 +272,7 @@
 
 // =============================================================================
 //
-LDBoundingBox& LDBoundingBox::operator<< (LDObject* obj)
+LDBoundingBox& LDBoundingBox::operator<< (LDObjectPtr obj)
 {
 	calcObject (obj);
 	return *this;
--- a/src/basics.h	Mon May 05 17:18:01 2014 +0300
+++ b/src/basics.h	Fri May 09 12:06:56 2014 +0300
@@ -22,11 +22,13 @@
 #include <QStringList>
 #include <QMetaType>
 #include <QVector3D>
+#include <QSharedPointer>
 #include "macros.h"
 
 class LDObject;
 class QFile;
 class QTextStream;
+class Matrix;
 
 using int8 = qint8;
 using int16 = qint16;
@@ -37,6 +39,10 @@
 using uint32 = quint32;
 using uint64 = quint64;
 using String = QString;
+using LDObjectPtr = QSharedPointer<LDObject>;
+using LDObjectList = QList<LDObjectPtr>;
+using LDObjectWeakPtr = QWeakPointer<LDObject>;
+using LDObjectWeakList = QList<LDObjectWeakPtr>;
 
 template<typename T, typename R>
 using Pair = std::pair<T, R>;
@@ -48,12 +54,6 @@
 	Z
 };
 
-// =============================================================================
-//
-class LDObject;
-class Matrix;
-using LDObjectList = QList<LDObject*>;
-
 //!
 //! Derivative of QVector3D: this class is used for the vertices.
 //!
@@ -192,7 +192,7 @@
 
 		//! Calculates the given \c obj to the bounding box, adjusting
 		//! extremas if necessary.
-		void calcObject (LDObject* obj);
+		void calcObject (LDObjectPtr obj);
 
 		//! Calculates the given \c vertex to the bounding box, adjusting
 		//! extremas if necessary.
@@ -202,7 +202,7 @@
 		Vertex center() const;
 
 		//! An operator overload for \c calcObject()
-		LDBoundingBox& operator<< (LDObject* obj);
+		LDBoundingBox& operator<< (LDObjectPtr obj);
 
 		//! An operator overload for \c calcVertex()
 		LDBoundingBox& operator<< (const Vertex& v);
--- a/src/editHistory.cc	Mon May 05 17:18:01 2014 +0300
+++ b/src/editHistory.cc	Fri May 09 12:06:56 2014 +0300
@@ -130,7 +130,7 @@
 //
 void AddHistory::undo() const
 {
-	LDObject* obj = parent()->document()->getObject (index());
+	LDObjectPtr obj = parent()->document()->getObject (index());
 	obj->destroy();
 }
 
@@ -138,14 +138,14 @@
 //
 void AddHistory::redo() const
 {
-	LDObject* obj = parseLine (code());
+	LDObjectPtr obj = parseLine (code());
 	parent()->document()->insertObj (index(), obj);
 	g_win->R()->compileObject (obj);
 }
 
 // =============================================================================
 //
-DelHistory::DelHistory (int idx, LDObject* obj) :
+DelHistory::DelHistory (int idx, LDObjectPtr obj) :
 	m_index (idx),
 	m_code (obj->asText()) {}
 
@@ -154,7 +154,7 @@
 //
 void DelHistory::undo() const
 {
-	LDObject* obj = parseLine (code());
+	LDObjectPtr obj = parseLine (code());
 	parent()->document()->insertObj (index(), obj);
 	g_win->R()->compileObject (obj);
 }
@@ -163,7 +163,7 @@
 //
 void DelHistory::redo() const
 {
-	LDObject* obj = parent()->document()->getObject (index());
+	LDObjectPtr obj = parent()->document()->getObject (index());
 	obj->destroy();
 }
 
@@ -171,8 +171,8 @@
 //
 void EditHistory::undo() const
 {
-	LDObject* obj = getCurrentDocument()->getObject (index());
-	LDObject* newobj = parseLine (oldCode());
+	LDObjectPtr obj = getCurrentDocument()->getObject (index());
+	LDObjectPtr newobj = parseLine (oldCode());
 	obj->replace (newobj);
 	g_win->R()->compileObject (newobj);
 }
@@ -181,8 +181,8 @@
 //
 void EditHistory::redo() const
 {
-	LDObject* obj = getCurrentDocument()->getObject (index());
-	LDObject* newobj = parseLine (newCode());
+	LDObjectPtr obj = getCurrentDocument()->getObject (index());
+	LDObjectPtr newobj = parseLine (newCode());
 	obj->replace (newobj);
 	g_win->R()->compileObject (newobj);
 }
--- a/src/editHistory.h	Mon May 05 17:18:01 2014 +0300
+++ b/src/editHistory.h	Fri May 09 12:06:56 2014 +0300
@@ -108,7 +108,7 @@
 
 	public:
 		IMPLEMENT_HISTORY_TYPE (Del)
-		DelHistory (int idx, LDObject* obj);
+		DelHistory (int idx, LDObjectPtr obj);
 };
 
 // =============================================================================
@@ -139,7 +139,7 @@
 	public:
 		IMPLEMENT_HISTORY_TYPE (Add)
 
-		AddHistory (int idx, LDObject* obj) :
+		AddHistory (int idx, LDObjectPtr obj) :
 			m_index (idx),
 			m_code (obj->asText()) {}
 };
--- a/src/extPrograms.cc	Mon May 05 17:18:01 2014 +0300
+++ b/src/extPrograms.cc	Fri May 09 12:06:56 2014 +0300
@@ -168,16 +168,16 @@
 //
 static void writeObjects (const LDObjectList& objects, QFile& f)
 {
-	for (LDObject* obj : objects)
+	for (LDObjectPtr obj : objects)
 	{
 		if (obj->type() == LDObject::ESubfile)
 		{
-			LDSubfile* ref = static_cast<LDSubfile*> (obj);
+			LDSubfilePtr ref = obj.staticCast<LDSubfile>();
 			LDObjectList objs = ref->inlineContents (true, false);
 
 			writeObjects (objs, f);
 
-			for (LDObject* obj : objs)
+			for (LDObjectPtr obj : objs)
 				obj->destroy();
 		}
 		else
@@ -219,7 +219,7 @@
 {
 	LDObjectList objects;
 
-	for (LDObject* obj : getCurrentDocument()->objects())
+	for (LDObjectPtr obj : getCurrentDocument()->objects())
 	{
 		if (not obj->isColored() || obj->color() != colnum)
 			continue;
@@ -315,7 +315,7 @@
 	// Insert the new objects
 	getCurrentDocument()->clearSelection();
 
-	for (LDObject* obj : objs)
+	for (LDObjectPtr obj : objs)
 	{
 		if (not obj->isScemantic())
 		{
--- a/src/glCompiler.cc	Mon May 05 17:18:01 2014 +0300
+++ b/src/glCompiler.cc	Fri May 09 12:06:56 2014 +0300
@@ -53,7 +53,7 @@
 static const QColor		g_BFCFrontColor (64, 192, 80);
 static const QColor		g_BFCBackColor (208, 64, 64);
 
-// static QMap<LDObject*, String> g_objectOrigins;
+// static QMap<LDObjectPtr, String> g_objectOrigins;
 
 // =============================================================================
 //
@@ -128,7 +128,7 @@
 
 // =============================================================================
 //
-QColor GLCompiler::getColorForPolygon (LDPolygon& poly, LDObject* topobj,
+QColor GLCompiler::getColorForPolygon (LDPolygon& poly, LDObjectPtr topobj,
 									   EVBOComplement complement) const
 {
 	QColor qcol;
@@ -224,21 +224,21 @@
 
 // =============================================================================
 //
-void GLCompiler::stageForCompilation (LDObject* obj)
+void GLCompiler::stageForCompilation (LDObjectPtr obj)
 {
 	/*
 	g_objectOrigins[obj] = format ("%1:%2 (%3)",
 		obj->document()->getDisplayName(), obj->lineNumber(), obj->typeName());
 	*/
 
-	m_staged << obj;
+	m_staged << LDObjectWeakPtr (obj);
 }
 
 // =============================================================================
 //
-void GLCompiler::unstage (LDObject* obj)
+void GLCompiler::unstage (LDObjectPtr obj)
 {
-	m_staged.removeOne (obj);
+	m_staged.removeOne (LDObjectWeakPtr (obj));
 }
 
 // =============================================================================
@@ -248,7 +248,7 @@
 	if (doc == null)
 		return;
 
-	for (LDObject* obj : doc->objects())
+	for (LDObjectPtr obj : doc->objects())
 		compileObject (obj);
 }
 
@@ -258,7 +258,7 @@
 {
 	removeDuplicates (m_staged);
 
-	for (LDObject* obj : m_staged)
+	for (LDObjectPtr obj : m_staged)
 		compileObject (obj);
 
 	m_staged.clear();
@@ -292,7 +292,7 @@
 
 // =============================================================================
 //
-void GLCompiler::dropObject (LDObject* obj)
+void GLCompiler::dropObject (LDObjectPtr obj)
 {
 	auto it = m_objectInfo.find (obj);
 
@@ -307,7 +307,7 @@
 
 // =============================================================================
 //
-void GLCompiler::compileObject (LDObject* obj)
+void GLCompiler::compileObject (LDObjectPtr obj)
 {
 //	print ("Compile %1\n", g_objectOrigins[obj]);
 
@@ -336,7 +336,7 @@
 
 		case LDObject::ESubfile:
 		{
-			LDSubfile* ref = static_cast<LDSubfile*> (obj);
+			LDSubfilePtr ref = obj.staticCast<LDSubfile>();
 			auto data = ref->inlinePolygons();
 
 			for (LDPolygon& poly : data)
@@ -357,7 +357,7 @@
 
 // =============================================================================
 //
-void GLCompiler::compilePolygon (LDPolygon& poly, LDObject* topobj, ObjectVBOInfo* objinfo)
+void GLCompiler::compilePolygon (LDPolygon& poly, LDObjectPtr topobj, ObjectVBOInfo* objinfo)
 {
 	EVBOSurface surface;
 	int numverts;
--- a/src/glCompiler.h	Mon May 05 17:18:01 2014 +0300
+++ b/src/glCompiler.h	Fri May 09 12:06:56 2014 +0300
@@ -36,15 +36,15 @@
 	GLCompiler (GLRenderer* renderer);
 	~GLCompiler();
 	void				compileDocument (LDDocument* doc);
-	void				dropObject (LDObject* obj);
+	void				dropObject (LDObjectPtr obj);
 	void				initialize();
-	QColor				getColorForPolygon (LDPolygon& poly, LDObject* topobj,
+	QColor				getColorForPolygon (LDPolygon& poly, LDObjectPtr topobj,
 											EVBOComplement complement) const;
 	QColor				indexColorForID (int id) const;
 	void				needMerge();
 	void				prepareVBO (int vbonum);
-	void				stageForCompilation (LDObject* obj);
-	void				unstage (LDObject* obj);
+	void				stageForCompilation (LDObjectPtr obj);
+	void				unstage (LDObjectPtr obj);
 
 	static uint32		colorToRGB (const QColor& color);
 
@@ -65,11 +65,11 @@
 
 private:
 	void			compileStaged();
-	void			compileObject (LDObject* obj);
-	void			compilePolygon (LDPolygon& poly, LDObject* topobj, GLCompiler::ObjectVBOInfo* objinfo);
+	void			compileObject (LDObjectPtr obj);
+	void			compilePolygon (LDPolygon& poly, LDObjectPtr topobj, GLCompiler::ObjectVBOInfo* objinfo);
 
-	QMap<LDObject*, ObjectVBOInfo>		m_objectInfo;
-	LDObjectList						m_staged; // Objects that need to be compiled
+	QMap<LDObjectPtr, ObjectVBOInfo>	m_objectInfo;
+	LDObjectWeakList					m_staged; // Objects that need to be compiled
 	GLuint								m_vbo[g_numVBOs];
 	bool								m_vboChanged[g_numVBOs];
 	int									m_vboSizes[g_numVBOs];
--- a/src/glRenderer.cc	Mon May 05 17:18:01 2014 +0300
+++ b/src/glRenderer.cc	Fri May 09 12:06:56 2014 +0300
@@ -126,7 +126,6 @@
 	m_position3D = g_origin;
 	m_toolTipTimer = new QTimer (this);
 	m_toolTipTimer->setSingleShot (true);
-	m_objectAtCursor = null;
 	m_isCameraMoving = false;
 	connect (m_toolTipTimer, SIGNAL (timeout()), this, SLOT (slot_toolTipTimer()));
 
@@ -1225,7 +1224,7 @@
 		LDObjectList oldsel = selection();
 		getCurrentDocument()->clearSelection();
 
-		for (LDObject* obj : oldsel)
+		for (LDObjectPtr obj : oldsel)
 			compileObject (obj);
 	}
 
@@ -1273,7 +1272,7 @@
 	// Read pixels from the color buffer.
 	glReadPixels (x0, m_height - y1, areawidth, areaheight, GL_RGBA, GL_UNSIGNED_BYTE, pixeldata);
 
-	LDObject* removedObj = null;
+	LDObjectPtr removedObj;
 	QList<qint32> indices;
 
 	// Go through each pixel read and add them to the selection.
@@ -1294,7 +1293,7 @@
 
 	for (qint32 idx : indices)
 	{
-		LDObject* obj = LDObject::fromID (idx);
+		LDObjectPtr obj = LDObject::fromID (idx);
 		assert (obj != null);
 
 		// If this is an additive single pick and the object is currently selected,
@@ -1318,7 +1317,7 @@
 	g_win->updateSelection();
 
 	// Recompile the objects now to update their color
-	for (LDObject* obj : selection())
+	for (LDObjectPtr obj : selection())
 		compileObject (obj);
 
 	if (removedObj)
@@ -1364,7 +1363,7 @@
 			LDObjectList priorsel = selection();
 			getCurrentDocument()->clearSelection();
 
-			for (LDObject* obj : priorsel)
+			for (LDObjectPtr obj : priorsel)
 				compileObject (obj);
 
 			g_win->updateSelection();
@@ -1442,7 +1441,7 @@
 		{
 			if (m_rectdraw)
 			{
-				LDQuad* quad = new LDQuad;
+				LDQuadPtr quad (spawn<LDQuad>());
 
 				// Copy the vertices from m_rectverts
 				updateRectVerts();
@@ -1460,7 +1459,7 @@
 					case 1:
 					{
 						// 1 vertex - add a vertex object
-						LDVertex* obj = new LDVertex;
+						LDVertexPtr obj = spawn<LDVertex>();
 						obj->pos = verts[0];
 						obj->setColor (maincolor);
 						objs << obj;
@@ -1469,7 +1468,7 @@
 					case 2:
 					{
 						// 2 verts - make a line
-						LDLine* obj = new LDLine (verts[0], verts[1]);
+						LDLinePtr obj = spawn<LDLine> (verts[0], verts[1]);
 						obj->setColor (edgecolor);
 						objs << obj;
 					} break;
@@ -1477,9 +1476,9 @@
 					case 3:
 					case 4:
 					{
-						LDObject* obj = (verts.size() == 3) ?
-							  static_cast<LDObject*> (new LDTriangle) :
-							  static_cast<LDObject*> (new LDQuad);
+						LDObjectPtr obj = (verts.size() == 3) ?
+							  static_cast<LDObjectPtr> (spawn<LDTriangle>()) :
+							  static_cast<LDObjectPtr> (spawn<LDQuad>());
 
 						obj->setColor (maincolor);
 
@@ -1531,7 +1530,7 @@
 						refFile->setImplicit (false);
 					}
 
-					LDSubfile* ref = new LDSubfile;
+					LDSubfilePtr ref = spawn<LDSubfile>();
 					ref->setFileInfo (refFile);
 					ref->setTransform (getCircleDrawMatrix (cmp.scale));
 					ref->setPosition (m_drawedVerts[0]);
@@ -1571,20 +1570,20 @@
 					v3.setCoordinate (relX, v3[relX] + c1[i].x1());
 					v3.setCoordinate (relY, v3[relY] + c1[i].y1());
 
-					LDQuad* q = new LDQuad (v0, v1, v2, v3);
-					q->setColor (maincolor);
+					LDQuadPtr quad (spawn<LDQuad> (v0, v1, v2, v3));
+					quad->setColor (maincolor);
 
 					// Ensure the quads always are BFC-front towards the camera
 					if (camera() % 3 <= 0)
-						q->invert();
+						quad->invert();
 
-					objs << q;
+					objs << quad;
 				}
 			}
 
 			if (circleOrDisc)
 			{
-				LDSubfile* ref = new LDSubfile;
+				LDSubfilePtr ref = spawn<LDSubfile>();
 				ref->setFileInfo (refFile);
 				ref->setTransform (transform);
 				ref->setPosition (m_drawedVerts[0]);
@@ -1603,7 +1602,7 @@
 
 	if (objs.size() > 0)
 	{
-		for (LDObject* obj : objs)
+		for (LDObjectPtr obj : objs)
 		{
 			document()->addObject (obj);
 			compileObject (obj);
@@ -1649,7 +1648,7 @@
 
 // =============================================================================
 //
-static QList<Vertex> getVertices (LDObject* obj)
+static QList<Vertex> getVertices (LDObjectPtr obj)
 {
 	QList<Vertex> verts;
 
@@ -1660,10 +1659,10 @@
 	}
 	elif (obj->type() == LDObject::ESubfile)
 	{
-		LDSubfile* ref = static_cast<LDSubfile*> (obj);
+		LDSubfilePtr ref = obj.staticCast<LDSubfile>();
 		LDObjectList objs = ref->inlineContents (true, false);
 
-		for (LDObject* obj : objs)
+		for (LDObjectPtr obj : objs)
 		{
 			verts << getVertices (obj);
 			obj->destroy();
@@ -1675,14 +1674,14 @@
 
 // =============================================================================
 //
-void GLRenderer::compileObject (LDObject* obj)
+void GLRenderer::compileObject (LDObjectPtr obj)
 {
 	compiler()->stageForCompilation (obj);
 }
 
 // =============================================================================
 //
-void GLRenderer::forgetObject (LDObject* obj)
+void GLRenderer::forgetObject (LDObjectPtr obj)
 {
 	compiler()->dropObject (obj);
 }
@@ -2003,7 +2002,7 @@
 	if (selection().isEmpty())
 		return;
 
-	LDObject* obj = selection().first();
+	LDObjectPtr obj = selection().first();
 	AddObjectDialog::staticDialog (obj->type(), obj);
 	g_win->endAction();
 	ev->accept();
@@ -2011,20 +2010,17 @@
 
 // =============================================================================
 //
-LDOverlay* GLRenderer::findOverlayObject (ECamera cam)
+LDOverlayPtr GLRenderer::findOverlayObject (ECamera cam)
 {
-	LDOverlay* ovlobj = null;
-
-	for (LDObject* obj : document()->objects())
+	for (LDObjectPtr obj : document()->objects())
 	{
-		if (obj->type() == LDObject::EOverlay && static_cast<LDOverlay*> (obj)->camera() == cam)
-		{
-			ovlobj = static_cast<LDOverlay*> (obj);
-			break;
-		}
+		LDOverlayPtr ovlobj = obj.dynamicCast<LDOverlay>();
+
+		if (ovlobj != null && obj.staticCast<LDOverlay>()->camera() == cam)
+			return ovlobj;
 	}
 
-	return ovlobj;
+	return LDOverlayPtr();
 }
 
 // =============================================================================
@@ -2039,16 +2035,20 @@
 			continue;
 
 		LDGLOverlay& meta = currentDocumentData().overlays[cam];
-		LDOverlay* ovlobj = findOverlayObject (cam);
+		LDOverlayPtr ovlobj = findOverlayObject (cam);
 
-		if (not ovlobj && meta.img)
+		if (ovlobj == null && meta.img != null)
 		{
 			delete meta.img;
 			meta.img = null;
 		}
-		elif (ovlobj && (meta.img == null || meta.fname != ovlobj->fileName()) && meta.invalid == false)
+		elif (ovlobj != null &&
+			(meta.img == null || meta.fname != ovlobj->fileName()) &&
+			not meta.invalid)
+		{
 			setupOverlay (cam, ovlobj->fileName(), ovlobj->x(),
 				ovlobj->y(), ovlobj->width(), ovlobj->height());
+		}
 	}
 }
 
@@ -2062,12 +2062,12 @@
 			continue;
 
 		LDGLOverlay& meta = currentDocumentData().overlays[cam];
-		LDOverlay* ovlobj = findOverlayObject (cam);
+		LDOverlayPtr ovlobj = findOverlayObject (cam);
 
 		if (meta.img == null && ovlobj != null)
 		{
 			// If this is the last overlay image, we need to remove the empty space after it as well.
-			LDObject* nextobj = ovlobj->next();
+			LDObjectPtr nextobj = ovlobj->next();
 
 			if (nextobj && nextobj->type() == LDObject::EEmpty)
 				nextobj->destroy();
@@ -2080,7 +2080,7 @@
 		{
 			// Inverse case: image is there but the overlay object is
 			// not, thus create the object.
-			ovlobj = new LDOverlay;
+			ovlobj = spawn<LDOverlay>();
 
 			// Find a suitable position to place this object. We want to place
 			// this into the header, which is everything up to the first scemantic
@@ -2093,7 +2093,7 @@
 
 			for (i = 0; i < document()->getObjectCount(); ++i)
 			{
-				LDObject* obj = document()->getObject (i);
+				LDObjectPtr obj = document()->getObject (i);
 
 				if (obj->isScemantic())
 				{
@@ -2112,7 +2112,7 @@
 				document()->insertObj (i, ovlobj);
 
 				if (found)
-					document()->insertObj (i + 1, new LDEmpty);
+					document()->insertObj (i + 1, spawn<LDEmpty>());
 			}
 		}
 
@@ -2138,8 +2138,8 @@
 	if (not cfg::highlightObjectBelowCursor && objectAtCursor() == null)
 		return;
 
-	LDObject* newObject = null;
-	LDObject* oldObject = objectAtCursor();
+	LDObjectWeakPtr newObject;
+	LDObjectWeakPtr oldObject = objectAtCursor();
 	qint32 newIndex;
 
 	if (isCameraMoving() || not cfg::highlightObjectBelowCursor)
@@ -2157,7 +2157,7 @@
 		newIndex = pixel[0] * 0x10000 | pixel[1] * 0x100 | pixel[2];
 	}
 
-	if (newIndex != (oldObject != null ? oldObject->id() : 0))
+	if (newIndex != (oldObject != null ? oldObject.toStrongRef()->id() : 0))
 	{
 		if (newIndex != 0)
 			newObject = LDObject::fromID (newIndex);
--- a/src/glRenderer.h	Mon May 05 17:18:01 2014 +0300
+++ b/src/glRenderer.h	Fri May 09 12:06:56 2014 +0300
@@ -146,7 +146,7 @@
 		PROPERTY (public,	LDDocument*,		document,		setDocument,		CUSTOM_WRITE)
 		PROPERTY (public,	EditMode,			editMode,		setEditMode,		CUSTOM_WRITE)
 		PROPERTY (private,	GLCompiler*,		compiler,		setCompiler,		STOCK_WRITE)
-		PROPERTY (public,	LDObject*,			objectAtCursor,	setObjectAtCursor,	STOCK_WRITE)
+		PROPERTY (public,	LDObjectWeakPtr,	objectAtCursor,	setObjectAtCursor,	STOCK_WRITE)
 		PROPERTY (private,	bool,				isCameraMoving,	setCameraMoving,	STOCK_WRITE)
 
 	public:
@@ -159,10 +159,10 @@
 		}
 
 		void           clearOverlay();
-		void           compileObject (LDObject* obj);
+		void           compileObject (LDObjectPtr obj);
 		void           drawGLScene();
 		void           endDraw (bool accept);
-		void           forgetObject (LDObject* obj);
+		void           forgetObject (LDObjectPtr obj);
 		Axis           getCameraAxis (bool y, ECamera camid = (ECamera) -1);
 		const char*    getCameraName() const;
 		double         getDepthValue() const;
@@ -230,7 +230,7 @@
 		QColor						m_bgcolor;
 
 		void           addDrawnVertex (Vertex m_hoverpos);
-		LDOverlay*     findOverlayObject (ECamera cam);
+		LDOverlayPtr findOverlayObject (ECamera cam);
 		void           updateRectVerts();
 		void           getRelativeAxes (Axis& relX, Axis& relY) const;
 		Axis			getRelativeZ() const;
--- a/src/ldDocument.cc	Mon May 05 17:18:01 2014 +0300
+++ b/src/ldDocument.cc	Fri May 09 12:06:56 2014 +0300
@@ -146,7 +146,7 @@
 	m_history->setIgnoring (true);
 
 	// Clear everything from the model
-	for (LDObject* obj : objects())
+	for (LDObjectPtr obj : objects())
 		obj->destroy();
 
 	delete history();
@@ -357,7 +357,7 @@
 	// User wishes to abort, so stop here now.
 	if (isAborted())
 	{
-		for (LDObject* obj : m_objects)
+		for (LDObjectPtr obj : m_objects)
 			obj->destroy();
 
 		m_objects.clear();
@@ -378,12 +378,13 @@
 		while (line.endsWith ("\n") || line.endsWith ("\r"))
 			line.chop (1);
 
-		LDObject* obj = parseLine (line);
+		LDObjectPtr obj = parseLine (line);
+		fprint (stderr, "got obj: %1\n", obj.data());
 
 		// Check for parse errors and warn about tthem
 		if (obj->type() == LDObject::EError)
 		{
-			print ("Couldn't parse line #%1: %2", progress() + 1, static_cast<LDError*> (obj)->reason());
+			print ("Couldn't parse line #%1: %2", progress() + 1, obj.staticCast<LDError>()->reason());
 
 			if (warnings() != null)
 				(*warnings())++;
@@ -735,11 +736,11 @@
 
 	// If the second object in the list holds the file name, update that now.
 	// Only do this if the file is explicitly open.
-	LDObject* nameObject = getObject (1);
+	LDObjectPtr nameObject = getObject (1);
 
 	if (not isImplicit() && nameObject != null && nameObject->type() == LDObject::EComment)
 	{
-		LDComment* nameComment = static_cast<LDComment*> (nameObject);
+		LDCommentPtr nameComment = nameObject.staticCast<LDComment>();
 
 		if (nameComment->text().left (6) == "Name: ")
 		{
@@ -751,7 +752,7 @@
 
 	// File is open, now save the model to it. Note that LDraw requires files to
 	// have DOS line endings, so we terminate the lines with \r\n.
-	for (LDObject* obj : objects())
+	for (LDObjectPtr obj : objects())
 		f.write ((obj->asText() + "\r\n").toUtf8());
 
 	// File is saved, now clean up.
@@ -828,7 +829,7 @@
 // code and returns the object parsed from it. parseLine never returns null,
 // the object will be LDError if it could not be parsed properly.
 // =============================================================================
-LDObject* parseLine (String line)
+LDObjectPtr parseLine (String line)
 {
 	try
 	{
@@ -837,7 +838,7 @@
 		if (tokens.size() <= 0)
 		{
 			// Line was empty, or only consisted of whitespace
-			return new LDEmpty;
+			return spawn<LDEmpty>();
 		}
 
 		if (tokens[0].length() != 1 || not tokens[0][0].isDigit())
@@ -858,17 +859,17 @@
 				{
 					for (int i = 0; i < LDBFC::NumStatements; ++i)
 						if (commentTextSimplified == format ("BFC %1", LDBFC::k_statementStrings [i]))
-							return new LDBFC ((LDBFC::Statement) i);
+							return spawn<LDBFC> ((LDBFC::Statement) i);
 
 					// MLCAD is notorious for stuffing these statements in parts it
 					// creates. The above block only handles valid statements, so we
 					// need to handle MLCAD-style invertnext, clip and noclip separately.
 					if (commentTextSimplified == "BFC CERTIFY INVERTNEXT")
-						return new LDBFC (LDBFC::InvertNext);
+						return spawn<LDBFC> (LDBFC::InvertNext);
 					elif (commentTextSimplified == "BFC CERTIFY CLIP")
-						return new LDBFC (LDBFC::Clip);
+						return spawn<LDBFC> (LDBFC::Clip);
 					elif (commentTextSimplified == "BFC CERTIFY NOCLIP")
-						return new LDBFC (LDBFC::NoClip);
+						return spawn<LDBFC> (LDBFC::NoClip);
 				}
 
 				if (tokens.size() > 2 && tokens[1] == "!LDFORGE")
@@ -880,7 +881,7 @@
 						checkTokenCount (line, tokens, 7);
 						checkTokenNumbers (line, tokens, 3, 6);
 
-						LDVertex* obj = new LDVertex;
+						LDVertexPtr obj = spawn<LDVertex>();
 						obj->setColor (tokens[3].toLong());
 						obj->pos.apply ([&](Axis ax, double& value) { value = tokens[4 + ax].toDouble(); });
 						return obj;
@@ -890,7 +891,7 @@
 						checkTokenCount (line, tokens, 9);
 						checkTokenNumbers (line, tokens, 5, 8);
 
-						LDOverlay* obj = new LDOverlay;
+						LDOverlayPtr obj = spawn<LDOverlay>();
 						obj->setFileName (tokens[3]);
 						obj->setCamera (tokens[4].toLong());
 						obj->setX (tokens[5].toLong());
@@ -902,7 +903,7 @@
 				}
 
 				// Just a regular comment:
-				LDComment* obj = new LDComment;
+				LDCommentPtr obj = spawn<LDComment>();
 				obj->setText (commentText);
 				return obj;
 			}
@@ -924,12 +925,12 @@
 				// here because the error object needs the document reference.
 				if (not load)
 				{
-					LDError* obj = new LDError (line, format ("Could not open %1", tokens[14]));
+					LDErrorPtr obj = spawn<LDError> (line, format ("Could not open %1", tokens[14]));
 					obj->setFileReferenced (tokens[14]);
 					return obj;
 				}
 
-				LDSubfile* obj = new LDSubfile;
+				LDSubfilePtr obj = spawn<LDSubfile>();
 				obj->setColor (tokens[1].toLong());
 				obj->setPosition (parseVertex (tokens, 2));  // 2 - 4
 
@@ -949,7 +950,7 @@
 				checkTokenNumbers (line, tokens, 1, 7);
 
 				// Line
-				LDLine* obj = new LDLine;
+				LDLinePtr obj (spawn<LDLine>());
 				obj->setColor (tokens[1].toLong());
 
 				for (int i = 0; i < 2; ++i)
@@ -964,7 +965,7 @@
 				checkTokenNumbers (line, tokens, 1, 10);
 
 				// Triangle
-				LDTriangle* obj = new LDTriangle;
+				LDTrianglePtr obj (spawn<LDTriangle>());
 				obj->setColor (tokens[1].toLong());
 
 				for (int i = 0; i < 3; ++i)
@@ -980,12 +981,12 @@
 				checkTokenNumbers (line, tokens, 1, 13);
 
 				// Quadrilateral / Conditional line
-				LDObject* obj;
+				LDObjectPtr obj;
 
 				if (num == 4)
-					obj = new LDQuad;
+					obj = spawn<LDQuad>();
 				else
-					obj = new LDCondLine;
+					obj = spawn<LDCondLine>();
 
 				obj->setColor (tokens[1].toLong());
 
@@ -1002,7 +1003,7 @@
 	catch (LDParseError& e)
 	{
 		// Strange line we couldn't parse
-		return new LDError (e.line(), e.error());
+		return spawn<LDError> (e.line(), e.error());
 	}
 }
 
@@ -1031,29 +1032,29 @@
 	g_loadedFiles << getCurrentDocument();
 
 	// Go through all objects in the current file and reload the subfiles
-	for (LDObject* obj : getCurrentDocument()->objects())
+	for (LDObjectPtr obj : getCurrentDocument()->objects())
 	{
 		if (obj->type() == LDObject::ESubfile)
 		{
-			LDSubfile* ref = static_cast<LDSubfile*> (obj);
+			LDSubfilePtr ref = obj.staticCast<LDSubfile>();
 			LDDocument* fileInfo = getDocument (ref->fileInfo()->name());
 
 			if (fileInfo)
 				ref->setFileInfo (fileInfo);
 			else
-				ref->replace (new LDError (ref->asText(), format ("Could not open %1", ref->fileInfo()->name())));
+				ref->replace (spawn<LDError> (ref->asText(), format ("Could not open %1", ref->fileInfo()->name())));
 		}
 
 		// Reparse gibberish files. It could be that they are invalid because
 		// of loading errors. Circumstances may be different now.
 		if (obj->type() == LDObject::EError)
-			obj->replace (parseLine (static_cast<LDError*> (obj)->contents()));
+			obj->replace (parseLine (obj.staticCast<LDError>()->contents()));
 	}
 }
 
 // =============================================================================
 //
-int LDDocument::addObject (LDObject* obj)
+int LDDocument::addObject (LDObjectPtr obj)
 {
 	history()->add (new AddHistory (objects().size(), obj));
 	m_objects << obj;
@@ -1073,14 +1074,14 @@
 //
 void LDDocument::addObjects (const LDObjectList objs)
 {
-	for (LDObject* obj : objs)
+	for (LDObjectPtr obj : objs)
 		if (obj)
 			addObject (obj);
 }
 
 // =============================================================================
 //
-void LDDocument::insertObj (int pos, LDObject* obj)
+void LDDocument::insertObj (int pos, LDObjectPtr obj)
 {
 	history()->add (new AddHistory (pos, obj));
 	m_objects.insert (pos, obj);
@@ -1096,14 +1097,14 @@
 
 // =============================================================================
 //
-void LDDocument::addKnownVerticesOf (LDObject* obj)
+void LDDocument::addKnownVerticesOf (LDObjectPtr obj)
 {
 	if (isImplicit())
 		return;
 
 	if (obj->type() == LDObject::ESubfile)
 	{
-		LDSubfile* ref = static_cast<LDSubfile*> (obj);
+		LDSubfilePtr ref = obj.staticCast<LDSubfile>();
 
 		for (Vertex vrt : ref->fileInfo()->inlineVertices())
 		{
@@ -1120,14 +1121,14 @@
 
 // =============================================================================
 //
-void LDDocument::removeKnownVerticesOf (LDObject* obj)
+void LDDocument::removeKnownVerticesOf (LDObjectPtr obj)
 {
 	if (isImplicit())
 		return;
 
 	if (obj->type() == LDObject::ESubfile)
 	{
-		LDSubfile* ref = static_cast<LDSubfile*> (obj);
+		LDSubfilePtr ref = obj.staticCast<LDSubfile>();
 
 		for (Vertex vrt : ref->fileInfo()->inlineVertices())
 		{
@@ -1144,7 +1145,7 @@
 
 // =============================================================================
 //
-void LDDocument::forgetObject (LDObject* obj)
+void LDDocument::forgetObject (LDObjectPtr obj)
 {
 	int idx = obj->lineNumber();
 	obj->deselect();
@@ -1211,7 +1212,7 @@
 
 // =============================================================================
 //
-void LDDocument::setObject (int idx, LDObject* obj)
+void LDDocument::setObject (int idx, LDObjectPtr obj)
 {
 	assert (idx >= 0 && idx < m_objects.size());
 
@@ -1249,10 +1250,10 @@
 
 // =============================================================================
 //
-LDObject* LDDocument::getObject (int pos) const
+LDObjectPtr LDDocument::getObject (int pos) const
 {
 	if (m_objects.size() <= pos)
-		return null;
+		return LDObjectPtr();
 
 	return m_objects[pos];
 }
@@ -1294,7 +1295,7 @@
 	LDObjectList objs = inlineContents (true, true);
 	m_storedVertices.clear();
 
-	for (LDObject* obj : objs)
+	for (LDObjectPtr obj : objs)
 	{
 		assert (obj->type() != LDObject::ESubfile);
 		LDPolygon* data = obj->getPolygon();
@@ -1343,7 +1344,7 @@
 
 	LDObjectList objs, objcache;
 
-	for (LDObject* obj : objects())
+	for (LDObjectPtr obj : objects())
 	{
 		// Skip those without scemantic meaning
 		if (not obj->isScemantic())
@@ -1353,10 +1354,10 @@
 		// just add it into the objects normally. Yay, recursion!
 		if (deep == true && obj->type() == LDObject::ESubfile)
 		{
-			LDSubfile* ref = static_cast<LDSubfile*> (obj);
+			LDSubfilePtr ref = obj.staticCast<LDSubfile>();
 			LDObjectList otherobjs = ref->inlineContents (deep, renderinline);
 
-			for (LDObject* otherobj : otherobjs)
+			for (LDObjectPtr otherobj : otherobjs)
 				objs << otherobj;
 		}
 		else
@@ -1448,7 +1449,7 @@
 
 // =============================================================================
 //
-void LDDocument::addToSelection (LDObject* obj) // [protected]
+void LDDocument::addToSelection (LDObjectPtr obj) // [protected]
 {
 	if (obj->isSelected())
 		return;
@@ -1461,7 +1462,7 @@
 
 // =============================================================================
 //
-void LDDocument::removeFromSelection (LDObject* obj) // [protected]
+void LDDocument::removeFromSelection (LDObjectPtr obj) // [protected]
 {
 	if (not obj->isSelected())
 		return;
@@ -1476,7 +1477,7 @@
 //
 void LDDocument::clearSelection()
 {
-	for (LDObject* obj : m_sel)
+	for (LDObjectPtr obj : m_sel)
 		removeFromSelection (obj);
 
 	assert (m_sel.isEmpty());
@@ -1491,7 +1492,7 @@
 
 // =============================================================================
 //
-void LDDocument::swapObjects (LDObject* one, LDObject* other)
+void LDDocument::swapObjects (LDObjectPtr one, LDObjectPtr other)
 {
 	int a = m_objects.indexOf (one);
 	int b = m_objects.indexOf (other);
--- a/src/ldDocument.h	Mon May 05 17:18:01 2014 +0300
+++ b/src/ldDocument.h	Fri May 09 12:06:56 2014 +0300
@@ -87,31 +87,31 @@
 		LDDocument();
 		~LDDocument();
 
-		int addObject (LDObject* obj); // Adds an object to this file at the end of the file.
+		int addObject (LDObjectPtr obj); // Adds an object to this file at the end of the file.
 		void addObjects (const LDObjectList objs);
 		void clearSelection();
-		void forgetObject (LDObject* obj); // Deletes the given object from the object chain.
+		void forgetObject (LDObjectPtr obj); // Deletes the given object from the object chain.
 		String getDisplayName();
 		const LDObjectList& getSelection() const;
 		bool hasUnsavedChanges() const; // Does this document have unsaved changes?
 		void initializeCachedData();
 		LDObjectList inlineContents (bool deep, bool renderinline);
-		void insertObj (int pos, LDObject* obj);
+		void insertObj (int pos, LDObjectPtr obj);
 		int getObjectCount() const;
-		LDObject* getObject (int pos) const;
+		LDObjectPtr getObject (int pos) const;
 		bool save (String path = ""); // Saves this file to disk.
-		void swapObjects (LDObject* one, LDObject* other);
+		void swapObjects (LDObjectPtr one, LDObjectPtr other);
 		bool isSafeToClose(); // Perform safety checks. Do this before closing any files!
-		void setObject (int idx, LDObject* obj);
+		void setObject (int idx, LDObjectPtr obj);
 		void addReference (LDDocumentPointer* ptr);
 		void removeReference (LDDocumentPointer* ptr);
 		QList<LDPolygon> inlinePolygons();
 		void vertexChanged (const Vertex& a, const Vertex& b);
-		void addKnownVerticesOf(LDObject* obj);
-		void removeKnownVerticesOf (LDObject* sub);
+		void addKnownVerticesOf(LDObjectPtr obj);
+		void removeKnownVerticesOf (LDObjectPtr sub);
 		QList<Vertex> inlineVertices();
 
-		inline LDDocument& operator<< (LDObject* obj)
+		inline LDDocument& operator<< (LDObjectPtr obj)
 		{
 			addObject (obj);
 			return *this;
@@ -152,8 +152,8 @@
 		static String shortenName (String a);
 
 	protected:
-		void addToSelection (LDObject* obj);
-		void removeFromSelection (LDObject* obj);
+		void addToSelection (LDObjectPtr obj);
+		void removeFromSelection (LDObjectPtr obj);
 
 		LDGLData* getGLData()
 		{
@@ -203,7 +203,7 @@
 void closeAll();
 
 // Parses a string line containing an LDraw object and returns the object parsed.
-LDObject* parseLine (String line);
+LDObjectPtr parseLine (String line);
 
 // Retrieves the pointer to the given document by file name. Document is loaded
 // from file if necessary. Can return null if neither succeeds.
--- a/src/ldObject.cc	Mon May 05 17:18:01 2014 +0300
+++ b/src/ldObject.cc	Fri May 09 12:06:56 2014 +0300
@@ -32,7 +32,7 @@
 CFGENTRY (Int, defaultLicense, 0);
 
 // List of all LDObjects
-static LDObjectList g_LDObjects;
+static LDObjectWeakList g_LDObjects;
 
 // =============================================================================
 // LDObject constructors
@@ -40,13 +40,12 @@
 LDObject::LDObject() :
 	m_isHidden (false),
 	m_isSelected (false),
-	m_parent (null),
 	m_document (null),
 	qObjListEntry (null)
 {
 	memset (m_coords, 0, sizeof m_coords);
 	chooseID();
-	g_LDObjects << this;
+	g_LDObjects << LDObjectWeakPtr (thisptr());
 	setRandomColor (QColor::fromHsv (rand() % 360, rand() % 256, rand() % 96 + 128));
 }
 
@@ -56,12 +55,13 @@
 {
 	int32 id = 1; // 0 shalt be null
 
-	for (LDObject* obj : g_LDObjects)
+	for (LDObjectWeakPtr obj : g_LDObjects)
 	{
-		assert (obj != this);
+		LDObjectPtr obj2 = obj.toStrongRef();
+		assert (obj2 != this);
 
-		if (obj->id() >= id)
-			id = obj->id() + 1;
+		if (obj2->id() >= id)
+			id = obj2->id() + 1;
 	}
 
 	setID (id);
@@ -189,7 +189,7 @@
 
 // =============================================================================
 //
-QList<LDTriangle*> LDQuad::splitToTriangles()
+QList<LDTrianglePtr> LDQuad::splitToTriangles()
 {
 	// Create the two triangles based on this quadrilateral:
 	// 0---3       0---3    3
@@ -197,22 +197,19 @@
 	// |   |  ==>  | /    / |
 	// |   |       |/    /  |
 	// 1---2       1    1---2
-	LDTriangle* tri1 = new LDTriangle (vertex (0), vertex (1), vertex (3));
-	LDTriangle* tri2 = new LDTriangle (vertex (1), vertex (2), vertex (3));
+	LDTrianglePtr tri1 (spawn<LDTriangle> (vertex (0), vertex (1), vertex (3)));
+	LDTrianglePtr tri2 (spawn<LDTriangle> (vertex (1), vertex (2), vertex (3)));
 
 	// The triangles also inherit the quad's color
 	tri1->setColor (color());
 	tri2->setColor (color());
 
-	QList<LDTriangle*> triangles;
-	triangles << tri1;
-	triangles << tri2;
-	return triangles;
+	return {tri1, tri2};
 }
 
 // =============================================================================
 //
-void LDObject::replace (LDObject* other)
+void LDObject::replace (LDObjectPtr other)
 {
 	long idx = lineNumber();
 	assert (idx != -1);
@@ -226,10 +223,10 @@
 
 // =============================================================================
 //
-void LDObject::swap (LDObject* other)
+void LDObject::swap (LDObjectPtr other)
 {
 	assert (document() == other->document());
-	document()->swapObjects (this, other);
+	document()->swapObjects (thisptr(), other);
 }
 
 // =============================================================================
@@ -252,6 +249,16 @@
 
 // =============================================================================
 //
+LDCondLine::LDCondLine (const Vertex& v0, const Vertex& v1, const Vertex& v2, const Vertex& v3)
+{
+	setVertex (0, v0);
+	setVertex (1, v1);
+	setVertex (2, v2);
+	setVertex (3, v3);
+}
+
+// =============================================================================
+//
 LDObject::~LDObject() {}
 
 // =============================================================================
@@ -268,25 +275,19 @@
 
 	// If this object was associated to a file, remove it off it now
 	if (document())
-		document()->forgetObject (this);
+		document()->forgetObject (thisptr());
 
 	// Delete the GL lists
-	g_win->R()->forgetObject (this);
+	g_win->R()->forgetObject (thisptr());
 
 	// Remove this object from the list of LDObjects
-	g_LDObjects.removeOne (this);
-
-	// The renderer's mouse-over field also needs to be cleared...
-	// Remind me to implement smart pointers someday.
-	if (g_win->R()->objectAtCursor() == this)
-		g_win->R()->setObjectAtCursor (null);
-
+	g_LDObjects.removeOne (LDObjectWeakPtr (thisptr()));
 	delete this;
 }
 
 // =============================================================================
 //
-static void transformObject (LDObject* obj, Matrix transform, Vertex pos, int parentcolor)
+static void transformObject (LDObjectPtr obj, Matrix transform, Vertex pos, int parentcolor)
 {
 	switch (obj->type())
 	{
@@ -306,10 +307,9 @@
 
 		case LDObject::ESubfile:
 		{
-			LDSubfile* ref = static_cast<LDSubfile*> (obj);
+			LDSubfilePtr ref = qSharedPointerCast<LDSubfile> (obj);
 			Matrix newMatrix = transform * ref->transform();
 			Vertex newpos = ref->position();
-
 			newpos.transform (transform, pos);
 			ref->setPosition (newpos);
 			ref->setTransform (newMatrix);
@@ -331,10 +331,10 @@
 	LDObjectList objs = fileInfo()->inlineContents (deep, render);
 
 	// Transform the objects
-	for (LDObject* obj : objs)
+	for (LDObjectPtr obj : objs)
 	{
 		// Set the parent now so we know what inlined the object.
-		obj->setParent (this);
+		obj->setParent (LDObjectWeakPtr (thisptr()));
 		transformObject (obj, transform(), position(), color());
 	}
 
@@ -408,7 +408,7 @@
 
 	for (long i = start; i != end; i += incr)
 	{
-		LDObject* obj = objs[i];
+		LDObjectPtr obj = objs[i];
 
 		const long idx = obj->lineNumber(),
 				   target = idx + (up ? -1 : 1);
@@ -432,7 +432,7 @@
 
 	// The objects need to be recompiled, otherwise their pick lists are left with
 	// the wrong index colors which messes up selection.
-	for (LDObject* obj : objsToCompile)
+	for (LDObjectPtr obj : objsToCompile)
 		g_win->R()->compileObject (obj);
 }
 
@@ -440,7 +440,7 @@
 //
 String LDObject::typeName (LDObject::Type type)
 {
-	LDObject* obj = LDObject::getDefault (type);
+	LDObjectPtr obj = LDObject::getDefault (type);
 	String name = obj->typeName();
 	obj->destroy();
 	return name;
@@ -459,7 +459,7 @@
 	{
 		int count = 0;
 
-		for (LDObject * obj : objs)
+		for (LDObjectPtr obj : objs)
 			if (obj->type() == objType)
 				count++;
 
@@ -483,41 +483,41 @@
 
 // =============================================================================
 //
-LDObject* LDObject::topLevelParent()
+LDObjectPtr LDObject::topLevelParent()
 {
 	if (parent() == null)
-		return this;
+		return thisptr();
 
-	LDObject* it = this;
+	LDObjectWeakPtr it (thisptr());
 
-	while (it->parent() != null)
-		it = it->parent();
+	while (it.toStrongRef()->parent() != null)
+		it = it.toStrongRef()->parent();
 
-	return it;
+	return it.toStrongRef();
 }
 
 // =============================================================================
 //
-LDObject* LDObject::next() const
+LDObjectPtr LDObject::next() const
 {
 	long idx = lineNumber();
 	assert (idx != -1);
 
 	if (idx == (long) document()->getObjectCount() - 1)
-		return null;
+		return LDObjectPtr();
 
 	return document()->getObject (idx + 1);
 }
 
 // =============================================================================
 //
-LDObject* LDObject::previous() const
+LDObjectPtr LDObject::previous() const
 {
 	long idx = lineNumber();
 	assert (idx != -1);
 
 	if (idx == 0)
-		return null;
+		return LDObjectPtr();
 
 	return document()->getObject (idx - 1);
 }
@@ -528,13 +528,13 @@
 {
 	if (hasMatrix())
 	{
-		LDMatrixObject* mo = dynamic_cast<LDMatrixObject*> (this);
+		LDMatrixObjectPtr mo = thisptr().dynamicCast<LDMatrixObject>();
 		mo->setPosition (mo->position() + vect);
 	}
 	elif (type() == LDObject::EVertex)
 	{
 		// ugh
-		static_cast<LDVertex*> (this)->pos += vect;
+		thisptr().staticCast<LDVertex>()->pos += vect;
 	}
 	else
 	{
@@ -545,25 +545,25 @@
 
 // =============================================================================
 //
-#define CHECK_FOR_OBJ(N) \
-	if (type == LDObject::E##N) \
-		return new LD##N;
-
-LDObject* LDObject::getDefault (const LDObject::Type type)
+LDObjectPtr LDObject::getDefault (const LDObject::Type type)
 {
-	CHECK_FOR_OBJ (Comment)
-	CHECK_FOR_OBJ (BFC)
-	CHECK_FOR_OBJ (Line)
-	CHECK_FOR_OBJ (CondLine)
-	CHECK_FOR_OBJ (Subfile)
-	CHECK_FOR_OBJ (Triangle)
-	CHECK_FOR_OBJ (Quad)
-	CHECK_FOR_OBJ (Empty)
-	CHECK_FOR_OBJ (BFC)
-	CHECK_FOR_OBJ (Error)
-	CHECK_FOR_OBJ (Vertex)
-	CHECK_FOR_OBJ (Overlay)
-	return null;
+	switch (type)
+	{
+		case EComment:		return spawn<LDComment>();
+		case EBFC:			return spawn<LDBFC>();
+		case ELine:			return spawn<LDLine>();
+		case ECondLine:		return spawn<LDCondLine>();
+		case ESubfile:		return spawn<LDSubfile>();
+		case ETriangle:		return spawn<LDTriangle>();
+		case EQuad:			return spawn<LDQuad>();
+		case EEmpty:		return spawn<LDEmpty>();
+		case EError:		return spawn<LDError>();
+		case EVertex:		return spawn<LDVertex>();
+		case EOverlay:		return spawn<LDOverlay>();
+		case EUnidentified:	assert (false);
+		case ENumTypes:		assert (false);
+	}
+	return LDObjectPtr();
 }
 
 // =============================================================================
@@ -613,9 +613,9 @@
 
 	if (idx > 0)
 	{
-		LDBFC* bfc = dynamic_cast<LDBFC*> (previous());
+		LDBFCPtr bfc = previous().dynamicCast<LDBFC>();
 
-		if (bfc && bfc->statement() == LDBFC::InvertNext)
+		if (not bfc.isNull() && bfc->statement() == LDBFC::InvertNext)
 		{
 			// This is prefixed with an invertnext, thus remove it.
 			bfc->destroy();
@@ -624,57 +624,55 @@
 	}
 
 	// Not inverted, thus prefix it with a new invertnext.
-	LDBFC* bfc = new LDBFC (LDBFC::InvertNext);
-	document()->insertObj (idx, bfc);
+	document()->insertObj (idx, spawn<LDBFC> (LDBFC::InvertNext));
 }
 
 // =============================================================================
 //
-static void invertLine (LDObject* line)
+void LDLine::invert()
 {
 	// For lines, we swap the vertices. I don't think that a
 	// cond-line's control points need to be swapped, do they?
-	Vertex tmp = line->vertex (0);
-	line->setVertex (0, line->vertex (1));
-	line->setVertex (1, tmp);
-}
-
-void LDLine::invert()
-{
-	invertLine (this);
+	Vertex tmp = vertex (0);
+	setVertex (0, vertex (1));
+	setVertex (1, tmp);
 }
 
 void LDCondLine::invert()
 {
-	invertLine (this);
+	static_cast<LDLine*> (this)->invert();
 }
 
 void LDVertex::invert() {}
 
 // =============================================================================
 //
-LDLine* LDCondLine::demote()
+LDLinePtr LDCondLine::demote()
 {
-	LDLine* repl = new LDLine;
+	LDLinePtr replacement (spawn<LDLine>());
 
-	for (int i = 0; i < repl->numVertices(); ++i)
-		repl->setVertex (i, vertex (i));
+	for (int i = 0; i < replacement->numVertices(); ++i)
+		replacement->setVertex (i, vertex (i));
 
-	repl->setColor (color());
+	replacement->setColor (color());
 
-	replace (repl);
-	return repl;
+	replace (replacement);
+	return replacement;
 }
 
 // =============================================================================
 //
-LDObject* LDObject::fromID (int id)
+LDObjectPtr LDObject::fromID (int id)
 {
-	for (LDObject* obj : g_LDObjects)
-		if (obj->id() == id)
+	for (LDObjectWeakPtr obj : g_LDObjects)
+	{
+		LDObjectPtr obj2 = obj.toStrongRef();
+
+		if (obj2->id() == id)
 			return obj;
+	}
 
-	return null;
+	return LDObjectPtr();
 }
 
 // =============================================================================
@@ -693,7 +691,8 @@
 // It takes care of history management so we can capture low-level changes, this
 // makes history stuff work out of the box.
 //
-template<class T> static void changeProperty (LDObject* obj, T* ptr, const T& val)
+template<typename T>
+static void changeProperty (LDObjectPtr obj, T* ptr, const T& val)
 {
 	long idx;
 
@@ -720,7 +719,7 @@
 //
 void LDObject::setColor (const int& val)
 {
-	changeProperty (this, &m_color, val);
+	changeProperty (thisptr(), &m_color, val);
 }
 
 // =============================================================================
@@ -737,7 +736,7 @@
 	if (document() != null)
 		document()->vertexChanged (*m_coords[i], vert);
 
-	changeProperty (this, &m_coords[i], LDSharedVertex::getSharedVertex (vert));
+	changeProperty (thisptr(), &m_coords[i], LDSharedVertex::getSharedVertex (vert));
 }
 
 // =============================================================================
@@ -786,14 +785,14 @@
 
 // =============================================================================
 //
-void LDSharedVertex::addRef (LDObject* a)
+void LDSharedVertex::addRef (LDObjectPtr a)
 {
 	m_refs << a;
 }
 
 // =============================================================================
 //
-void LDSharedVertex::delRef (LDObject* a)
+void LDSharedVertex::delRef (LDObjectPtr a)
 {
 	m_refs.removeOne (a);
 
@@ -809,7 +808,7 @@
 void LDObject::select()
 {
 	assert (document() != null);
-	document()->addToSelection (this);
+	document()->addToSelection (thisptr());
 }
 
 // =============================================================================
@@ -817,7 +816,7 @@
 void LDObject::deselect()
 {
 	assert (document() != null);
-	document()->removeFromSelection (this);
+	document()->removeFromSelection (thisptr());
 }
 
 // =============================================================================
@@ -842,45 +841,9 @@
 
 // =============================================================================
 //
-LDObject* LDObject::createCopy() const
+LDObjectPtr LDObject::createCopy() const
 {
-	/*
-	LDObject* copy = clone();
-	copy->setFile (null);
-	copy->chooseID();
-	copy->setSelected (false);
-	*/
-
-	/*
-	LDObject* copy = getDefault (getType());
-	copy->setColor (color());
-
-	if (hasMatrix())
-	{
-		LDMatrixObject* copyMo = static_cast<LDMatrixObject*> (copy);
-		const LDMatrixObject* mo = static_cast<const LDMatrixObject*> (this);
-		copyMo->setPosition (mo->getPosition());
-		copyMo->setTransform (mo->transform());
-	}
-	else
-	{
-		for (int i = 0; i < vertices(); ++i)
-			copy->setVertex (getVertex (i));
-	}
-
-	switch (getType())
-	{
-		case Subfile:
-		{
-			LDSubfile* copyRef = static_cast<LDSubfile*> (copy);
-			const LDSubfile* ref = static_cast<const LDSubfile*> (this);
-
-			copyRef->setFileInfo (ref->fileInfo());
-		}
-	}
-	*/
-
-	LDObject* copy = parseLine (asText());
+	LDObjectPtr copy = parseLine (asText());
 	return copy;
 }
 
@@ -889,7 +852,7 @@
 void LDSubfile::setFileInfo (const LDDocumentPointer& a)
 {
 	if (document() != null)
-		document()->removeKnownVerticesOf (this);
+		document()->removeKnownVerticesOf (thisptr());
 
 	m_fileInfo = a;
 
@@ -904,5 +867,5 @@
 	}
 
 	if (document() != null)
-		document()->addKnownVerticesOf (this);
+		document()->addKnownVerticesOf (thisptr());
 };
--- a/src/ldObject.h	Mon May 05 17:18:01 2014 +0300
+++ b/src/ldObject.h	Fri May 09 12:06:56 2014 +0300
@@ -17,37 +17,34 @@
  */
 
 #pragma once
+#include <type_traits>
 #include "main.h"
 #include "basics.h"
 #include "misc/documentPointer.h"
 #include "glShared.h"
 
-#define LDOBJ(T)										\
-protected:												\
-	virtual LD##T* clone() override						\
-	{													\
-		return new LD##T (*this);						\
-	}													\
-														\
-public:													\
-	virtual LDObject::Type type() const override		\
-	{													\
-		return LDObject::E##T;							\
-	}													\
-	virtual String asText() const override;				\
-	virtual void invert() override;
+#define LDOBJ(T)												\
+public:															\
+	virtual LDObject::Type type() const override				\
+	{															\
+		return LDObject::E##T;									\
+	}															\
+	virtual String asText() const override;						\
+	virtual void invert() override;								\
+protected:														\
+	friend class QSharedPointer<LD##T>::ExternalRefCount;		\
 
-#define LDOBJ_NAME(N)          virtual String typeName() const override { return #N; }
-#define LDOBJ_VERTICES(V)      virtual int numVertices() const override { return V; }
-#define LDOBJ_SETCOLORED(V)    virtual bool isColored() const override { return V; }
+#define LDOBJ_NAME(N)          public: virtual String typeName() const override { return #N; }
+#define LDOBJ_VERTICES(V)      public: virtual int numVertices() const override { return V; }
+#define LDOBJ_SETCOLORED(V)    public: virtual bool isColored() const override { return V; }
 #define LDOBJ_COLORED          LDOBJ_SETCOLORED (true)
 #define LDOBJ_UNCOLORED        LDOBJ_SETCOLORED (false)
 
-#define LDOBJ_CUSTOM_SCEMANTIC virtual bool isScemantic() const override
+#define LDOBJ_CUSTOM_SCEMANTIC public: virtual bool isScemantic() const override
 #define LDOBJ_SCEMANTIC        LDOBJ_CUSTOM_SCEMANTIC { return true; }
 #define LDOBJ_NON_SCEMANTIC    LDOBJ_CUSTOM_SCEMANTIC { return false; }
 
-#define LDOBJ_SETMATRIX(V)     virtual bool hasMatrix() const override { return V; }
+#define LDOBJ_SETMATRIX(V)     public: virtual bool hasMatrix() const override { return V; }
 #define LDOBJ_HAS_MATRIX       LDOBJ_SETMATRIX (true)
 #define LDOBJ_NO_MATRIX        LDOBJ_SETMATRIX (false)
 
@@ -66,13 +63,13 @@
 // =============================================================================
 class LDObject
 {
-	PROPERTY (public,		bool,			isHidden,		setHidden,		STOCK_WRITE)
-	PROPERTY (public,		bool,			isSelected,		setSelected,	STOCK_WRITE)
-	PROPERTY (public,		LDObject*,		parent,			setParent,		STOCK_WRITE)
-	PROPERTY (public,		LDDocument*,	document,		setDocument,	STOCK_WRITE)
-	PROPERTY (private,		int,			id,				setID,			STOCK_WRITE)
-	PROPERTY (public,		int,			color,			setColor,		CUSTOM_WRITE)
-	PROPERTY (private,		QColor,			randomColor,	setRandomColor,	STOCK_WRITE)
+	PROPERTY (public,		bool,				isHidden,		setHidden,		STOCK_WRITE)
+	PROPERTY (public,		bool,				isSelected,		setSelected,	STOCK_WRITE)
+	PROPERTY (public,		LDObjectWeakPtr,	parent,			setParent,		STOCK_WRITE)
+	PROPERTY (public,		LDDocument*,		document,		setDocument,	STOCK_WRITE)
+	PROPERTY (private,		int,				id,				setID,			STOCK_WRITE)
+	PROPERTY (public,		int,				color,			setColor,		CUSTOM_WRITE)
+	PROPERTY (private,		QColor,				randomColor,	setRandomColor,	STOCK_WRITE)
 
 	public:
 		// Object type codes.
@@ -101,7 +98,7 @@
 		virtual String				asText() const = 0;
 
 		// Makes a copy of this object
-		LDObject*					createCopy() const;
+		LDObjectPtr					createCopy() const;
 
 		// Deletes this object
 		void						destroy();
@@ -128,16 +125,16 @@
 		void						move (Vertex vect);
 
 		// Object after this in the current file
-		LDObject*					next() const;
+		LDObjectPtr					next() const;
 
 		// Number of vertices this object has
 		virtual int					numVertices() const = 0;
 
 		// Object prior to this in the current file
-		LDObject*					previous() const;
+		LDObjectPtr					previous() const;
 
 		// Replace this LDObject with another LDObject. Object is deleted in the process.
-		void						replace (LDObject* other);
+		void						replace (LDObjectPtr other);
 
 		// Selects this object.
 		void						select();
@@ -149,10 +146,10 @@
 		void						setVertexCoord (int i, Axis ax, double value);
 
 		// Swap this object with another.
-		void						swap (LDObject* other);
+		void						swap (LDObjectPtr other);
 
 		// What object in the current file ultimately references this?
-		LDObject*					topLevelParent();
+		LDObjectPtr					topLevelParent();
 
 		// Type enumerator of this object
 		virtual Type				type() const = 0;
@@ -167,14 +164,14 @@
 		static String typeName (LDObject::Type type);
 
 		// Returns a default-constructed LDObject by the given type
-		static LDObject* getDefault (const LDObject::Type type);
+		static LDObjectPtr getDefault (const LDObject::Type type);
 
 		// TODO: move this to LDDocument?
 		static void moveObjects (LDObjectList objs, const bool up);
 
 		// Get a description of a list of LDObjects
 		static String describeObjects (const LDObjectList& objs);
-		static LDObject* fromID (int id);
+		static LDObjectPtr fromID (int id);
 		LDPolygon* getPolygon();
 
 		// TODO: make this private!
@@ -190,13 +187,44 @@
 		virtual ~LDObject();
 		void chooseID();
 
+		// Even though we supply a custom deleter to QSharedPointer, the shared
+		// pointer's base class still calls operator delete directly in one of
+		// its methods. The method should never be called but we need to declare
+		// the class making this delete call a friend anyway.
+		friend class QSharedPointer<LDObject>::ExternalRefCount;
+
+		inline LDObjectPtr thisptr()
+		{
+			return LDObjectPtr (this);
+		}
+
 	private:
-		virtual LDObject* clone() = 0;
 		LDSharedVertex*	m_coords[4];
 };
 
+//
+// Makes a new LDObject. This makes the shared pointer always use the custom
+// deleter so that all deletions go through destroy();
+//
+template<typename T, typename... Args>
+inline QSharedPointer<T> spawn (Args... args)
+{
+	static_assert (std::is_base_of<LDObject, T>::value, "spawn may only be used with LDObject-derivatives");
+	return QSharedPointer<T> (new T (args...), [](T* obj){ obj->destroy(); });
+}
+
 NUMERIC_ENUM_OPERATORS (LDObject::Type)
 
+//
+// Apparently QWeakPointer doesn't implement operator<. This is a problem when
+// some of the code needs to sort and remove duplicates from LDObject lists.
+// Adding a specialized version here:
+//
+inline bool operator< (LDObjectWeakPtr a, LDObjectWeakPtr b)
+{
+	return a.data() < b.data();
+}
+
 // =============================================================================
 // LDSharedVertex
 //
@@ -215,8 +243,8 @@
 			return m_data;
 		}
 
-		void addRef (LDObject* a);
-		void delRef (LDObject* a);
+		void addRef (LDObjectPtr a);
+		void delRef (LDObjectPtr a);
 
 		static LDSharedVertex* getSharedVertex (const Vertex& a);
 
@@ -243,7 +271,7 @@
 //
 class LDMatrixObject
 {
-	PROPERTY (public,	LDObject*,	linkPointer,	setLinkPointer,	STOCK_WRITE)
+	PROPERTY (public,	LDObjectPtr,	linkPointer,	setLinkPointer,	STOCK_WRITE)
 	PROPERTY (public,	Matrix,		transform,		setTransform,	CUSTOM_WRITE)
 
 	public:
@@ -279,6 +307,9 @@
 		LDSharedVertex*	m_position;
 };
 
+using LDMatrixObjectPtr = QSharedPointer<LDMatrixObject>;
+using LDMatrixObjectWeakPtr = QWeakPointer<LDMatrixObject>;
+
 // =============================================================================
 //
 // Represents a line in the LDraw file that could not be properly parsed. It is
@@ -304,6 +335,9 @@
 			m_reason (reason) {}
 };
 
+using LDErrorPtr = QSharedPointer<LDError>;
+using LDErrorWeakPtr = QWeakPointer<LDError>;
+
 // =============================================================================
 //
 // Represents an empty line in the LDraw code file.
@@ -318,6 +352,9 @@
 	LDOBJ_NO_MATRIX
 };
 
+using LDEmptyPtr = QSharedPointer<LDEmpty>;
+using LDEmptyWeakPtr = QWeakPointer<LDEmpty>;
+
 // =============================================================================
 //
 // Represents a code-0 comment in the LDraw code file.
@@ -337,6 +374,9 @@
 		LDComment (String text) : m_text (text) {}
 };
 
+using LDCommentPtr = QSharedPointer<LDComment>;
+using LDCommentWeakPtr = QWeakPointer<LDComment>;
+
 // =============================================================================
 //
 // Represents a 0 BFC statement in the LDraw code. eStatement contains the type
@@ -377,6 +417,9 @@
 		static const char* k_statementStrings[];
 };
 
+using LDBFCPtr = QSharedPointer<LDBFC>;
+using LDBFCWeakPtr = QWeakPointer<LDBFC>;
+
 // =============================================================================
 // LDSubfile
 //
@@ -405,7 +448,7 @@
 
 		LDSubfile()
 		{
-			setLinkPointer (this);
+			setLinkPointer (QSharedPointer<LDSubfile> (this));
 		}
 
 		// Inlines this subfile. Note that return type is an array of heap-allocated
@@ -418,6 +461,8 @@
 };
 
 Q_DECLARE_OPERATORS_FOR_FLAGS (LDSubfile::InlineFlags)
+using LDSubfilePtr = QSharedPointer<LDSubfile>;
+using LDSubfileWeakPtr = QWeakPointer<LDSubfile>;
 
 // =============================================================================
 // LDLine
@@ -440,6 +485,9 @@
 		LDLine (Vertex v1, Vertex v2);
 };
 
+using LDLinePtr = QSharedPointer<LDLine>;
+using LDLineWeakPtr = QWeakPointer<LDLine>;
+
 // =============================================================================
 // LDCondLine
 //
@@ -457,9 +505,13 @@
 
 	public:
 		LDCondLine() {}
-		LDLine* demote();
+		LDCondLine (const Vertex& v0, const Vertex& v1, const Vertex& v2, const Vertex& v3);
+		LDLinePtr demote();
 };
 
+using LDCondLinePtr = QSharedPointer<LDCondLine>;
+using LDCondLineWeakPtr = QWeakPointer<LDCondLine>;
+
 // =============================================================================
 // LDTriangle
 //
@@ -486,6 +538,9 @@
 		}
 };
 
+using LDTrianglePtr = QSharedPointer<LDTriangle>;
+using LDTriangleWeakPtr = QWeakPointer<LDTriangle>;
+
 // =============================================================================
 // LDQuad
 //
@@ -506,9 +561,12 @@
 		LDQuad (const Vertex& v0, const Vertex& v1, const Vertex& v2, const Vertex& v3);
 
 		// Split this quad into two triangles (note: heap-allocated)
-		QList<LDTriangle*> splitToTriangles();
+		QList<LDTrianglePtr> splitToTriangles();
 };
 
+using LDQuadPtr = QSharedPointer<LDQuad>;
+using LDQuadWeakPtr = QWeakPointer<LDQuad>;
+
 // =============================================================================
 // LDVertex
 //
@@ -532,6 +590,9 @@
 		Vertex pos;
 };
 
+using LDVertexPtr = QSharedPointer<LDVertex>;
+using LDVertexWeakPtr = QWeakPointer<LDVertex>;
+
 // =============================================================================
 // LDOverlay
 //
@@ -546,14 +607,17 @@
 	LDOBJ_UNCOLORED
 	LDOBJ_NON_SCEMANTIC
 	LDOBJ_NO_MATRIX
-	PROPERTY (public,	int,	 camera,	setCamera,		STOCK_WRITE)
-	PROPERTY (public,	int,	 x,			setX,			STOCK_WRITE)
-	PROPERTY (public,	int,	 y,			setY,			STOCK_WRITE)
-	PROPERTY (public,	int,	 width,		setWidth,		STOCK_WRITE)
-	PROPERTY (public,	int,	 height,	setHeight,		STOCK_WRITE)
-	PROPERTY (public,	String, fileName,	setFileName,	STOCK_WRITE)
+	PROPERTY (public,	int,		camera,		setCamera,		STOCK_WRITE)
+	PROPERTY (public,	int,		x,			setX,			STOCK_WRITE)
+	PROPERTY (public,	int,		y,			setY,			STOCK_WRITE)
+	PROPERTY (public,	int,		width,		setWidth,		STOCK_WRITE)
+	PROPERTY (public,	int,		height,		setHeight,		STOCK_WRITE)
+	PROPERTY (public,	String,		fileName,	setFileName,	STOCK_WRITE)
 };
 
+using LDOverlayPtr = QSharedPointer<LDOverlay>;
+using LDOverlayWeakPtr = QWeakPointer<LDOverlay>;
+
 // Other common LDraw stuff
 static const String g_CALicense ("!LICENSE Redistributable under CCAL version 2.0 : see CAreadme.txt");
 static const String g_nonCALicense ("!LICENSE Not redistributable : see NonCAreadme.txt");
--- a/src/main.cc	Mon May 05 17:18:01 2014 +0300
+++ b/src/main.cc	Fri May 09 12:06:56 2014 +0300
@@ -43,6 +43,12 @@
 
 CFGENTRY (Bool, firstStart, true);
 
+static void deleteline (LDLine* obj)
+{
+	fprintf (stderr, "delete %p\n", obj);
+	delete obj;
+}
+
 // =============================================================================
 //
 int main (int argc, char* argv[])
@@ -68,7 +74,15 @@
 	initColors();
 	MainWindow* win = new MainWindow;
 	newFile();
-	win->show();
+	//win->show();
+
+	QSharedPointer<LDLine> obj (new LDLine, &deleteline);
+	fprint (stderr, "%1: %2\n", obj.data(), obj->type());
+	//class A { public: virtual ~A(){} virtual int foo() = 0; void destroy() { delete this; }};
+	//class B : public A { public: virtual ~B(){} virtual int foo() override { return 5; }};
+	//QSharedPointer<A> a (new B, [](A* p) { p->destroy(); });
+	//fprintf (stderr, "%p (%lu bytes)\n", a.data(), sizeof *a);
+	exit (0);
 
 	// If this is the first start, get the user to configuration. Especially point
 	// them to the profile tab, it's the most important form to fill in.
--- a/src/mainWindow.cc	Mon May 05 17:18:01 2014 +0300
+++ b/src/mainWindow.cc	Fri May 09 12:06:56 2014 +0300
@@ -264,7 +264,7 @@
 			getCurrentDocument()->getObject (0)->type() == LDObject::EComment)
 		{
 			// Append title
-			LDComment* comm = static_cast<LDComment*> (getCurrentDocument()->getObject (0));
+			LDCommentPtr comm = getCurrentDocument()->getObject (0).staticCast<LDComment>();
 			title += format (": %1", comm->text());
 		}
 
@@ -294,7 +294,7 @@
 	LDObjectList selCopy = selection();
 
 	// Delete the objects that were being selected
-	for (LDObject* obj : selCopy)
+	for (LDObjectPtr obj : selCopy)
 		obj->destroy();
 
 	refresh();
@@ -318,7 +318,7 @@
 
 	ui->objectList->clear();
 
-	for (LDObject* obj : getCurrentDocument()->objects())
+	for (LDObjectPtr obj : getCurrentDocument()->objects())
 	{
 		String descr;
 
@@ -326,7 +326,7 @@
 		{
 			case LDObject::EComment:
 			{
-				descr = static_cast<LDComment*> (obj)->text();
+				descr = obj.staticCast<LDComment>()->text();
 
 				// Remove leading whitespace
 				while (descr[0] == ' ')
@@ -361,13 +361,13 @@
 
 			case LDObject::EVertex:
 			{
-				descr = static_cast<LDVertex*> (obj)->pos.toString (true);
+				descr = obj.staticCast<LDVertex>()->pos.toString (true);
 				break;
 			}
 
 			case LDObject::ESubfile:
 			{
-				LDSubfile* ref = static_cast<LDSubfile*> (obj);
+				LDSubfilePtr ref = obj.staticCast<LDSubfile>();
 
 				descr = format ("%1 %2, (", ref->fileInfo()->getDisplayName(), ref->position().toString (true));
 
@@ -380,13 +380,13 @@
 
 			case LDObject::EBFC:
 			{
-				descr = LDBFC::k_statementStrings[static_cast<LDBFC*> (obj)->statement()];
+				descr = LDBFC::k_statementStrings[obj.staticCast<LDBFC>()->statement()];
 				break;
 			}
 
 			case LDObject::EOverlay:
 			{
-				LDOverlay* ovl = static_cast<LDOverlay*> (obj);
+				LDOverlayPtr ovl = obj.staticCast<LDOverlay>();
 				descr = format ("[%1] %2 (%3, %4), %5 x %6", g_CameraNames[ovl->camera()],
 					basename (ovl->fileName()), ovl->x(), ovl->y(),
 					ovl->width(), ovl->height());
@@ -444,7 +444,7 @@
 	if (selection().isEmpty())
 		return;
 
-	LDObject* obj = selection().last();
+	LDObjectPtr obj = selection().last();
 	ui->objectList->scrollToItem (obj->qObjListEntry);
 }
 
@@ -461,7 +461,7 @@
 	getCurrentDocument()->clearSelection();
 	const QList<QListWidgetItem*> items = ui->objectList->selectedItems();
 
-	for (LDObject* obj : getCurrentDocument()->objects())
+	for (LDObjectPtr obj : getCurrentDocument()->objects())
 	{
 		for (QListWidgetItem* item : items)
 		{
@@ -477,7 +477,7 @@
 	LDObjectList compound = priorSelection + selection();
 	removeDuplicates (compound);
 
-	for (LDObject* obj : compound)
+	for (LDObjectPtr obj : compound)
 		R()->compileObject (obj);
 
 	R()->update();
@@ -512,7 +512,7 @@
 
 	int newColor = col->index;
 
-	for (LDObject* obj : selection())
+	for (LDObjectPtr obj : selection())
 	{
 		if (not obj->isColored())
 			continue; // uncolored object
@@ -561,7 +561,7 @@
 
 	ui->objectList->clearSelection();
 
-	for (LDObject* obj : selection())
+	for (LDObjectPtr obj : selection())
 	{
 		if (obj->qObjListEntry == null)
 			continue;
@@ -578,7 +578,7 @@
 {
 	int result = -1;
 
-	for (LDObject* obj : selection())
+	for (LDObjectPtr obj : selection())
 	{
 		if (not obj->isColored())
 			continue; // doesn't use color
@@ -599,7 +599,7 @@
 {
 	LDObject::Type result = LDObject::EUnidentified;
 
-	for (LDObject* obj : selection())
+	for (LDObjectPtr obj : selection())
 	{
 		if (result != LDObject::EUnidentified && obj->color() != result)
 			return LDObject::EUnidentified;
@@ -634,7 +634,7 @@
 void MainWindow::spawnContextMenu (const QPoint pos)
 {
 	const bool single = (selection().size() == 1);
-	LDObject* singleObj = (single) ? selection()[0] : null;
+	LDObjectPtr singleObj = single ? selection().first() : LDObjectPtr();
 
 	QMenu* contextMenu = new QMenu;
 
@@ -661,7 +661,7 @@
 	contextMenu->addAction (ui->actionModeDraw);
 	contextMenu->addAction (ui->actionModeCircle);
 
-	if (selection().size() > 0)
+	if (not selection().isEmpty())
 	{
 		contextMenu->addSeparator();
 		contextMenu->addAction (ui->actionSubfileSelection);
@@ -682,7 +682,7 @@
 {
 	LDObjectList objs;
 
-	for (LDObject* obj : getCurrentDocument()->objects())
+	for (LDObjectPtr obj : getCurrentDocument()->objects())
 	{
 		if (not obj->isColored() || obj->color() != colnum)
 			continue;
@@ -690,7 +690,7 @@
 		objs << obj;
 	}
 
-	for (LDObject* obj : objs)
+	for (LDObjectPtr obj : objs)
 		obj->destroy();
 }
 
@@ -708,18 +708,14 @@
 //
 void MainWindow::slot_editObject (QListWidgetItem* listitem)
 {
-	LDObject* obj = null;
-
-	for (LDObject* it : getCurrentDocument()->objects())
+	for (LDObjectPtr it : getCurrentDocument()->objects())
 	{
 		if (it->qObjListEntry == listitem)
 		{
-			obj = it;
+			AddObjectDialog::staticDialog (it->type(), it);
 			break;
 		}
 	}
-
-	AddObjectDialog::staticDialog (obj->type(), obj);
 }
 
 // =============================================================================
@@ -852,7 +848,7 @@
 {
 	std::map<int, int> counts;
 
-	for (LDObject* obj : getCurrentDocument()->objects())
+	for (LDObjectPtr obj : getCurrentDocument()->objects())
 	{
 		if (not obj->isColored())
 			continue;
@@ -970,7 +966,7 @@
 	ui->objectList->clear();
 	LDDocument* f = getCurrentDocument();
 
-for (LDObject* obj : *f)
+for (LDObjectPtr obj : *f)
 		ui->objectList->addItem (obj->qObjListEntry);
 
 #endif
--- a/src/miscallenous.cc	Mon May 05 17:18:01 2014 +0300
+++ b/src/miscallenous.cc	Fri May 09 12:06:56 2014 +0300
@@ -210,10 +210,10 @@
 			LDBoundingBox box;
 
 			// Calculate center vertex
-			for (LDObject* obj : objs)
+			for (LDObjectPtr obj : objs)
 			{
 				if (obj->hasMatrix())
-					box << dynamic_cast<LDMatrixObject*> (obj)->position();
+					box << obj.dynamicCast<LDMatrixObject>()->position();
 				else
 					box << obj;
 			}
--- a/src/partDownloader.cc	Mon May 05 17:18:01 2014 +0300
+++ b/src/partDownloader.cc	Fri May 09 12:06:56 2014 +0300
@@ -455,9 +455,9 @@
 	// from unknown file references, try resolve that by downloading the reference.
 	// This is why downloading a part may end up downloading multiple files, as
 	// it resolves dependencies.
-	for (LDObject* obj : f->objects())
+	for (LDObjectPtr obj : f->objects())
 	{
-		LDError* err = dynamic_cast<LDError*> (obj);
+		LDErrorPtr err = obj.dynamicCast<LDError>();
 
 		if (err == null || err->fileReferenced().isEmpty())
 			continue;
--- a/src/primitives.cc	Mon May 05 17:18:01 2014 +0300
+++ b/src/primitives.cc	Fri May 09 12:06:56 2014 +0300
@@ -406,7 +406,7 @@
 				Vertex v0 (x0, 0.0f, z0),
 				  v1 (x1, 0.0f, z1);
 
-				LDLine* line = new LDLine;
+				LDLinePtr line (spawn<LDLine>());
 				line->setVertex (0, v0);
 				line->setVertex (1, v1);
 				line->setColor (edgecolor);
@@ -456,12 +456,8 @@
 					   v2 (x2, y2, z2),
 					   v3 (x3, y3, z3);
 
-				LDQuad* quad = new LDQuad;
+				LDQuadPtr quad (spawn<LDQuad> (v0, v1, v2, v3));
 				quad->setColor (maincolor);
-				quad->setVertex (0, v0);
-				quad->setVertex (1, v1);
-				quad->setVertex (2, v2);
-				quad->setVertex (3, v3);
 
 				if (type == Cylinder)
 					quad->invert();
@@ -491,7 +487,7 @@
 
 				// Disc negatives need to go the other way around, otherwise
 				// they'll end up upside-down.
-				LDTriangle* seg = new LDTriangle;
+				LDTrianglePtr seg (spawn<LDTriangle>());
 				seg->setColor (maincolor);
 				seg->setVertex (type == Disc ? 0 : 2, v0);
 				seg->setVertex (1, v1);
@@ -514,7 +510,9 @@
 		  v3 (radialPoint (i - 1, divs, cos), 0.0f, radialPoint (i - 1, divs, sin));
 
 		if (type == Cylinder)
+		{
 			v1 = Vertex (v0[X], 1.0f, v0[Z]);
+		}
 		elif (type == Cone)
 		{
 			v1 = Vertex (v0[X] * (num + 1), 0.0f, v0[Z] * (num + 1));
@@ -523,7 +521,7 @@
 			v0.setZ (v0.z() * num);
 		}
 
-		LDCondLine* line = new LDCondLine;
+		LDCondLinePtr line = (spawn<LDCondLine>());
 		line->setColor (edgecolor);
 		line->setVertex (0, v0);
 		line->setVertex (1, v1);
@@ -619,18 +617,18 @@
 		author = format ("%1 [%2]", cfg::defaultName, cfg::defaultUser);
 	}
 
-	f->addObjects (
-	{
-		new LDComment (descr),
-		new LDComment (format ("Name: %1", name)),
-		new LDComment (format ("Author: %1", author)),
-		new LDComment (format ("!LDRAW_ORG Unofficial_%1Primitive", divs == g_hires ? "48_" : "")),
-		new LDComment (license),
-		new LDEmpty,
-		new LDBFC (LDBFC::CertifyCCW),
-		new LDEmpty,
-	});
+	LDObjectList objs;
 
+	objs << spawn<LDComment> (descr)
+		 << spawn<LDComment> (format ("Name: %1", name))
+		 << spawn<LDComment> (format ("Author: %1", author))
+		 << spawn<LDComment> (format ("!LDRAW_ORG Unofficial_%1Primitive", divs == g_hires ? "48_" : ""))
+		 << spawn<LDComment> (license)
+		 << spawn<LDEmpty>()
+		 << spawn<LDBFC> (LDBFC::CertifyCCW)
+		 << spawn<LDEmpty>();
+
+	f->addObjects (objs);
 	f->addObjects (makePrimitive (type, segs, divs, num));
 	return f;
 }

mercurial