- made LDDocument use shared pointers, this eliminates a lot of document-related crashes

Mon, 02 Jun 2014 12:50:40 +0300

author
Santeri Piippo <crimsondusk64@gmail.com>
date
Mon, 02 Jun 2014 12:50:40 +0300
changeset 784
f82ab4d3c7b4
parent 783
1db20d88650f
child 785
2a8e4bbb5a94

- made LDDocument use shared pointers, this eliminates a lot of document-related crashes

src/actions.cc file | annotate | diff | comparison | revisions
src/addObjectDialog.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/format.h 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/mainWindow.h file | annotate | diff | comparison | revisions
src/misc/documentPointer.cc file | annotate | diff | comparison | revisions
src/misc/documentPointer.h file | annotate | diff | comparison | revisions
src/miscallenous.cc file | annotate | diff | comparison | revisions
src/partDownloader.cc file | annotate | diff | comparison | revisions
src/partDownloader.h file | annotate | diff | comparison | revisions
src/primitives.cc file | annotate | diff | comparison | revisions
src/primitives.h file | annotate | diff | comparison | revisions
--- a/src/actions.cc	Sun Jun 01 03:15:36 2014 +0300
+++ b/src/actions.cc	Mon Jun 02 12:50:40 2014 +0300
@@ -149,13 +149,8 @@
 //
 DEFINE_ACTION (SaveAll, CTRL (L))
 {
-	for (LDDocument* file : g_loadedFiles)
-	{
-		if (file->isImplicit())
-			continue;
-
+	for (LDDocumentPtr file : LDDocument::explicitDocuments())
 		save (file, false);
-	}
 }
 
 // =============================================================================
@@ -165,7 +160,7 @@
 	if (not getCurrentDocument()->isSafeToClose())
 		return;
 
-	delete getCurrentDocument();
+	getCurrentDocument()->dismiss();
 }
 
 // =============================================================================
@@ -626,7 +621,7 @@
 // these is an immense pain.
 DEFINE_ACTION (testpic, "Test picture", "", "", (0))
 {
-	LDDocument* file = getFile ("axle.dat");
+	LDDocumentPtr file = getFile ("axle.dat");
 	setlocale (LC_ALL, "C");
 
 	if (not file)
@@ -827,7 +822,7 @@
 		code << obj->asText();
 
 	// Create the new subfile document
-	LDDocument* doc = new LDDocument;
+	LDDocumentPtr doc = LDDocument::createNew();
 	doc->setImplicit (false);
 	doc->setFullPath (fullsubname);
 	doc->setName (LDDocument::shortenName (fullsubname));
@@ -862,8 +857,6 @@
 		for (LDObjectPtr obj : selection())
 			obj->destroy();
 
-		g_loadedFiles << doc;
-
 		// Add a reference to the new subfile to where the selection was
 		LDSubfilePtr ref (spawn<LDSubfile>());
 		ref->setColor (maincolor);
@@ -879,7 +872,7 @@
 	else
 	{
 		// Failed to save.
-		delete doc;
+		doc->dismiss();
 	}
 }
 
--- a/src/addObjectDialog.cc	Sun Jun 01 03:15:36 2014 +0300
+++ b/src/addObjectDialog.cc	Mon Jun 02 12:50:40 2014 +0300
@@ -410,7 +410,7 @@
 			if (name.length() == 0)
 				return; // no subfile filename
 
-			LDDocument* file = getDocument (name);
+			LDDocumentPtr file = getDocument (name);
 
 			if (not file)
 			{
--- a/src/basics.h	Sun Jun 01 03:15:36 2014 +0300
+++ b/src/basics.h	Mon Jun 02 12:50:40 2014 +0300
@@ -29,6 +29,7 @@
 class QFile;
 class QTextStream;
 class Matrix;
+class LDDocument;
 
 using int8 = qint8;
 using int16 = qint16;
@@ -43,6 +44,8 @@
 using LDObjectList = QList<LDObjectPtr>;
 using LDObjectWeakPtr = QWeakPointer<LDObject>;
 using LDObjectWeakList = QList<LDObjectWeakPtr>;
+using LDDocumentPtr = QSharedPointer<LDDocument>;
+using LDDocumentWeakPtr = QWeakPointer<LDDocument>;
 
 template<typename T, typename R>
 using Pair = std::pair<T, R>;
--- a/src/editHistory.cc	Sun Jun 01 03:15:36 2014 +0300
+++ b/src/editHistory.cc	Mon Jun 02 12:50:40 2014 +0300
@@ -130,7 +130,7 @@
 //
 void AddHistory::undo() const
 {
-	LDObjectPtr obj = parent()->document()->getObject (index());
+	LDObjectPtr obj = parent()->document().toStrongRef()->getObject (index());
 	obj->destroy();
 }
 
@@ -139,7 +139,7 @@
 void AddHistory::redo() const
 {
 	LDObjectPtr obj = parseLine (code());
-	parent()->document()->insertObj (index(), obj);
+	parent()->document().toStrongRef()->insertObj (index(), obj);
 	g_win->R()->compileObject (obj);
 }
 
@@ -155,7 +155,7 @@
 void DelHistory::undo() const
 {
 	LDObjectPtr obj = parseLine (code());
-	parent()->document()->insertObj (index(), obj);
+	parent()->document().toStrongRef()->insertObj (index(), obj);
 	g_win->R()->compileObject (obj);
 }
 
@@ -163,7 +163,7 @@
 //
 void DelHistory::redo() const
 {
-	LDObjectPtr obj = parent()->document()->getObject (index());
+	LDObjectPtr obj = parent()->document().toStrongRef()->getObject (index());
 	obj->destroy();
 }
 
--- a/src/editHistory.h	Sun Jun 01 03:15:36 2014 +0300
+++ b/src/editHistory.h	Mon Jun 02 12:50:40 2014 +0300
@@ -40,9 +40,9 @@
 // =============================================================================
 class History
 {
-	PROPERTY (private,	int,			position,	setPosition,	STOCK_WRITE)
-	PROPERTY (public,	LDDocument*,	document,	setDocument,	STOCK_WRITE)
-	PROPERTY (public,	bool,			isIgnoring,	setIgnoring,	STOCK_WRITE)
+	PROPERTY (private,	int,				position,	setPosition,	STOCK_WRITE)
+	PROPERTY (public,	LDDocumentWeakPtr,	document,	setDocument,	STOCK_WRITE)
+	PROPERTY (public,	bool,				isIgnoring,	setIgnoring,	STOCK_WRITE)
 
 	public:
 		typedef QList<AbstractHistoryEntry*> Changeset;
--- a/src/format.h	Sun Jun 01 03:15:36 2014 +0300
+++ b/src/format.h	Mon Jun 02 12:50:40 2014 +0300
@@ -47,6 +47,18 @@
 		}
 
 		template<typename T>
+		StringFormatArg (QSharedPointer<T> const& a)
+		{
+			m_text.sprintf ("%p", a.data());
+		}
+
+		template<typename T>
+		StringFormatArg (QWeakPointer<T> const& a)
+		{
+			m_text.sprintf ("%p", a.data());
+		}
+
+		template<typename T>
 		StringFormatArg (const QList<T>& a)
 		{
 			m_text = "{";
--- a/src/glCompiler.cc	Sun Jun 01 03:15:36 2014 +0300
+++ b/src/glCompiler.cc	Mon Jun 02 12:50:40 2014 +0300
@@ -243,7 +243,7 @@
 
 // =============================================================================
 //
-void GLCompiler::compileDocument (LDDocument* doc)
+void GLCompiler::compileDocument (LDDocumentPtr doc)
 {
 	if (doc == null)
 		return;
@@ -278,7 +278,9 @@
 
 	for (auto it = m_objectInfo.begin(); it != m_objectInfo.end(); ++it)
 	{
-		if (it.key()->document() == getCurrentDocument() && not it.key()->isHidden())
+		if (it.key() == null)
+			it = m_objectInfo.erase (it);
+		elif (it.key().toStrongRef()->document() == getCurrentDocument() && not it.key().toStrongRef()->isHidden())
 			vbodata += it->data[vbonum];
 	}
 
@@ -311,7 +313,7 @@
 {
 //	print ("Compile %1\n", g_objectOrigins[obj]);
 
-	if (obj == null || obj->document() == null || obj->document()->isImplicit())
+	if (obj == null || obj->document() == null || obj->document().toStrongRef()->isImplicit())
 		return;
 
 	ObjectVBOInfo info;
--- a/src/glCompiler.h	Sun Jun 01 03:15:36 2014 +0300
+++ b/src/glCompiler.h	Mon Jun 02 12:50:40 2014 +0300
@@ -35,7 +35,7 @@
 
 	GLCompiler (GLRenderer* renderer);
 	~GLCompiler();
-	void				compileDocument (LDDocument* doc);
+	void				compileDocument (LDDocumentPtr doc);
 	void				dropObject (LDObjectPtr obj);
 	void				initialize();
 	QColor				getColorForPolygon (LDPolygon& poly, LDObjectPtr topobj,
@@ -68,12 +68,12 @@
 	void			compileObject (LDObjectPtr obj);
 	void			compilePolygon (LDPolygon& poly, LDObjectPtr topobj, GLCompiler::ObjectVBOInfo* objinfo);
 
-	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];
-	GLRenderer* const					m_renderer;
+	QMap<LDObjectWeakPtr, 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];
+	GLRenderer* const						m_renderer;
 };
 
 #define checkGLError() { checkGLError_private (__FILE__, __LINE__); }
--- a/src/glRenderer.cc	Sun Jun 01 03:15:36 2014 +0300
+++ b/src/glRenderer.cc	Mon Jun 02 12:50:40 2014 +0300
@@ -119,7 +119,6 @@
 	m_rectdraw = false;
 	m_panning = false;
 	m_compiler = new GLCompiler (this);
-	setDocument (null);
 	setDrawOnly (false);
 	setMessageLog (null);
 	m_width = m_height = -1;
@@ -1371,7 +1370,7 @@
 
 // =============================================================================
 //
-void GLRenderer::setDocument (LDDocument* const& a)
+void GLRenderer::setDocument (LDDocumentPtr const& a)
 {
 	m_document = a;
 
@@ -1500,7 +1499,7 @@
 			const int segs = g_lores, divs = g_lores; // TODO: make customizable
 			double dist0 = getCircleDrawDist (0),
 				dist1 = getCircleDrawDist (1);
-			LDDocument* refFile = null;
+			LDDocumentPtr refFile;
 			Matrix transform;
 			bool circleOrDisc = false;
 
--- a/src/glRenderer.h	Sun Jun 01 03:15:36 2014 +0300
+++ b/src/glRenderer.h	Mon Jun 02 12:50:40 2014 +0300
@@ -143,7 +143,7 @@
 		PROPERTY (public,	bool,				isDrawOnly,		setDrawOnly,		STOCK_WRITE)
 		PROPERTY (public,	MessageManager*,	messageLog, 	setMessageLog,		STOCK_WRITE)
 		PROPERTY (private,	bool,				isPicking,		setPicking,			CUSTOM_WRITE)
-		PROPERTY (public,	LDDocument*,		document,		setDocument,		CUSTOM_WRITE)
+		PROPERTY (public,	LDDocumentPtr,		document,		setDocument,		CUSTOM_WRITE)
 		PROPERTY (public,	EditMode,			editMode,		setEditMode,		CUSTOM_WRITE)
 		PROPERTY (private,	GLCompiler*,		compiler,		setCompiler,		STOCK_WRITE)
 		PROPERTY (public,	LDObjectWeakPtr,	objectAtCursor,	setObjectAtCursor,	STOCK_WRITE)
--- a/src/ldDocument.cc	Sun Jun 01 03:15:36 2014 +0300
+++ b/src/ldDocument.cc	Mon Jun 02 12:50:40 2014 +0300
@@ -41,10 +41,11 @@
 static bool g_loadingMainFile = false;
 static const int g_maxRecentFiles = 10;
 static bool g_aborted = false;
-static LDDocumentPointer g_logoedStud = null;
-static LDDocumentPointer g_logoedStud2 = null;
-
-LDDocument* LDDocument::m_curdoc = null;
+static LDDocumentPtr g_logoedStud;
+static LDDocumentPtr g_logoedStud2;
+static QList<LDDocumentWeakPtr> g_allDocuments;
+static QList<LDDocumentPtr> g_explicitDocuments;
+static LDDocumentPtr g_currentDocument;
 
 const QStringList g_specialSubdirectories ({ "s", "48", "8" });
 
@@ -123,75 +124,98 @@
 
 // =============================================================================
 //
-LDDocument::LDDocument() :
+LDDocument::LDDocument (LDDocumentPtr* selfptr) :
+	m_isImplicit (true),
 	m_flags (0),
 	m_gldata (new LDGLData)
 {
-	setImplicit (true);
+	*selfptr = LDDocumentPtr (this);
+	setSelf (*selfptr);
 	setSavePosition (-1);
 	setTabIndex (-1);
 	setHistory (new History);
-	history()->setDocument (this);
+	history()->setDocument (*selfptr);
 	m_needsReCache = true;
+	g_allDocuments << *selfptr;
+}
+
+// =============================================================================
+//
+LDDocumentPtr LDDocument::createNew()
+{
+	LDDocumentPtr ptr;
+	new LDDocument (&ptr);
+	return ptr;
 }
 
 // =============================================================================
 //
 LDDocument::~LDDocument()
 {
-	// Remove this file from the list of files. This MUST be done FIRST, otherwise
-	// a ton of other functions will think this file is still valid when it is not!
-	g_loadedFiles.removeOne (this);
+	print ("Deleted %1", getDisplayName());
+	g_allDocuments.removeOne (self());
 	m_flags |= DOCF_IsBeingDestroyed;
-	m_history->setIgnoring (true);
-
-	// Clear everything from the model
-	for (LDObjectPtr obj : objects())
-		obj->destroy();
-
-	delete history();
+	delete m_history;
 	delete m_gldata;
-
-	// If we just closed the current file, we need to set the current
-	// file as something else.
-	if (this == getCurrentDocument())
-	{
-		bool found = false;
-
-		// Try find an explicitly loaded file - if we can't find one,
-		// we need to create a new file to switch to.
-		for (LDDocument* file : g_loadedFiles)
-		{
-			if (not file->isImplicit())
-			{
-				LDDocument::setCurrent (file);
-				found = true;
-				break;
-			}
-		}
-
-		if (not found)
-			newFile();
-	}
-
-	if (this == g_logoedStud)
-		g_logoedStud = null;
-	elif (this == g_logoedStud2)
-		g_logoedStud2 = null;
-
-	g_win->updateDocumentList();
-	print ("Closed %1", name());
 }
 
 // =============================================================================
 //
-LDDocument* findDocument (String name)
+extern QMap<long, LDObjectWeakPtr>	g_allObjects;
+void LDDocument::setImplicit (bool const& a)
 {
-	for (LDDocument * file : g_loadedFiles)
-		if (not file->name().isEmpty() && file->name() == name)
+	if (m_isImplicit != a)
+	{
+		m_isImplicit = a;
+
+		if (a == false)
+			g_explicitDocuments << self().toStrongRef();
+		else
+		{
+			g_explicitDocuments.removeOne (self().toStrongRef());
+			print ("Closed %1", name());
+			int count = 0;
+			for (LDObjectPtr obj : g_allObjects)
+			{
+				LDSubfilePtr ref = obj.dynamicCast<LDSubfile>();
+				if (ref && ref->fileInfo() == self())
+					count++;
+			}
+		}
+
+		if (g_win != null)
+			g_win->updateDocumentList();
+
+		// If the current document just became implicit (e.g. it was 'closed'),
+		// we need to get a new current document.
+		if (current() == self() && isImplicit())
+		{
+			if (explicitDocuments().isEmpty())
+				newFile();
+			else
+				setCurrent (explicitDocuments().first());
+		}
+	}
+}
+
+// =============================================================================
+//
+QList<LDDocumentPtr> const& LDDocument::explicitDocuments()
+{
+	return g_explicitDocuments;
+}
+
+// =============================================================================
+//
+LDDocumentPtr findDocument (String name)
+{
+	for (LDDocumentPtr file : g_allDocuments)
+	{
+		if (file->name() == name)
 			return file;
+	}
 
-	return null;
+	return LDDocumentPtr();
 }
 
 // =============================================================================
@@ -240,7 +264,7 @@
 	// in the immediate vicinity of a current model to override stock LDraw stuff.
 	String reltop = basename (dirname (relpath));
 
-	for (LDDocument* doc : g_loadedFiles)
+	for (LDDocumentPtr doc : g_allDocuments)
 	{
 		if (doc->fullPath().isEmpty())
 			continue;
@@ -298,6 +322,8 @@
 	return "";
 }
 
+// =============================================================================
+//
 QFile* openLDrawFile (String relpath, bool subdirs, String* pathpointer)
 {
 	print ("Opening %1...\n", relpath);
@@ -467,12 +493,13 @@
 		*ok = not loader->isAborted();
 
 	objs = loader->objects();
+	delete loader;
 	return objs;
 }
 
 // =============================================================================
 //
-LDDocument* openDocument (String path, bool search, bool implicit)
+LDDocumentPtr openDocument (String path, bool search, bool implicit, LDDocumentPtr fileToOverride)
 {
 	// Convert the file name to lowercase since some parts contain uppercase
 	// file names. I'll assume here that the library will always use lowercase
@@ -490,21 +517,19 @@
 		if (not fp->open (QIODevice::ReadOnly))
 		{
 			delete fp;
-			return null;
+			return LDDocumentPtr();
 		}
 	}
 
 	if (not fp)
-		return null;
+		return LDDocumentPtr();
 
-	LDDocument* load = new LDDocument;
+	LDDocumentPtr load = (fileToOverride != null ? fileToOverride : LDDocument::createNew());
 	load->setImplicit (implicit);
 	load->setFullPath (fullpath);
 	load->setName (LDDocument::shortenName (load->fullPath()));
-	dprint ("name: %1 (%2)", load->name(), load->fullPath());
-	g_loadedFiles << load;
 
-	// Don't take the file loading as actual edits to the file
+	// Loading the file shouldn't count as actual edits to the document.
 	load->history()->setIgnoring (true);
 
 	int numWarnings;
@@ -515,9 +540,8 @@
 
 	if (not ok)
 	{
-		g_loadedFiles.removeOne (load);
-		delete load;
-		return null;
+		load->dismiss();
+		return LDDocumentPtr();
 	}
 
 	load->addObjects (objs);
@@ -593,11 +617,8 @@
 //
 void closeAll()
 {
-	// Remove all loaded files and the objects they contain
-	QList<LDDocument*> files = g_loadedFiles;
-
-	for (LDDocument* file : files)
-		delete file;
+	for (LDDocumentPtr file : g_explicitDocuments)
+		file->dismiss();
 }
 
 // =============================================================================
@@ -605,10 +626,9 @@
 void newFile()
 {
 	// Create a new anonymous file and set it to our current
-	LDDocument* f = new LDDocument;
+	LDDocumentPtr f = LDDocument::createNew();
 	f->setName ("");
 	f->setImplicit (false);
-	g_loadedFiles << f;
 	LDDocument::setCurrent (f);
 	LDDocument::closeInitialFile();
 	g_win->R()->setDocument (f);
@@ -650,15 +670,14 @@
 // =============================================================================
 void openMainFile (String path)
 {
-	g_loadingMainFile = true;
-
 	// If there's already a file with the same name, this file must replace it.
-	LDDocument* documentToReplace = null;
+	LDDocumentPtr documentToReplace;
+	LDDocumentPtr file;
 	String shortName = LDDocument::shortenName (path);
 
-	for (LDDocument* doc : g_loadedFiles)
+	for (LDDocumentWeakPtr doc : g_allDocuments)
 	{
-		if (doc->name() == shortName)
+		if (doc.toStrongRef()->name() == shortName)
 		{
 			documentToReplace = doc;
 			break;
@@ -668,19 +687,22 @@
 	// We cannot open this file if the document this would replace is not
 	// safe to close.
 	if (documentToReplace != null && not documentToReplace->isSafeToClose())
+		return;
+
+	g_loadingMainFile = true;
+
+	// If we're replacing an existing document, clear the document and
+	// make it ready for being loaded to.
+	if (documentToReplace != null)
 	{
-		g_loadingMainFile = false;
-		return;
+		file = documentToReplace;
+		file->clear();
 	}
 
-	LDDocument* file = openDocument (path, false, false);
+	file = openDocument (path, false, false, file);
 
-	if (not file)
+	if (file == null)
 	{
-		// Loading failed, thus drop down to a new file since we
-		// closed everything prior.
-		newFile();
-
 		if (not g_aborted)
 		{
 			// Tell the user loading failed.
@@ -694,20 +716,6 @@
 
 	file->setImplicit (false);
 
-	// Replace references to the old file with the new file.
-	if (documentToReplace != null)
-	{
-		for (LDDocumentPointer* ptr : documentToReplace->references())
-		{	dprint ("ptr: %1 (%2)\n",
-				ptr, ptr->pointer() ? ptr->pointer()->name() : "<null>");
-
-			*ptr = file;
-		}
-
-		assert (documentToReplace->references().isEmpty());
-		delete documentToReplace;
-	}
-
 	// If we have an anonymous, unchanged file open as the only open file
 	// (aside of the one we just opened), close it now.
 	LDDocument::closeInitialFile();
@@ -766,13 +774,21 @@
 	setFullPath (savepath);
 	setName (shortenName (savepath));
 
-	g_win->updateDocumentListItem (this);
+	g_win->updateDocumentListItem (self().toStrongRef());
 	g_win->updateTitle();
 	return true;
 }
 
 // =============================================================================
 //
+void LDDocument::clear()
+{
+	for (LDObjectPtr obj : objects())
+		forgetObject (obj);
+}
+
+// =============================================================================
+//
 static void checkTokenCount (const QStringList& tokens, int num)
 {
 	if (tokens.size() != num)
@@ -903,7 +919,7 @@
 				// not loading the main file now, but the subfile in question.
 				bool tmp = g_loadingMainFile;
 				g_loadingMainFile = false;
-				LDDocument* load = getDocument (tokens[14]);
+				LDDocumentPtr load = getDocument (tokens[14]);
 				g_loadingMainFile = tmp;
 
 				// If we cannot open the file, mark it an error. Note we cannot use LDParseError
@@ -994,10 +1010,10 @@
 
 // =============================================================================
 //
-LDDocument* getDocument (String filename)
+LDDocumentPtr getDocument (String filename)
 {
 	// Try find the file in the list of loaded files
-	LDDocument* doc = findDocument (filename);
+	LDDocumentPtr doc = findDocument (filename);
 
 	// If it's not loaded, try open it
 	if (not doc)
@@ -1013,16 +1029,13 @@
 	if (not getCurrentDocument())
 		return;
 
-	g_loadedFiles.clear();
-	g_loadedFiles << getCurrentDocument();
-
 	// Go through all objects in the current file and reload the subfiles
 	for (LDObjectPtr obj : getCurrentDocument()->objects())
 	{
 		if (obj->type() == LDObject::ESubfile)
 		{
 			LDSubfilePtr ref = obj.staticCast<LDSubfile>();
-			LDDocument* fileInfo = getDocument (ref->fileInfo()->name());
+			LDDocumentPtr fileInfo = getDocument (ref->fileInfo()->name());
 
 			if (fileInfo)
 				ref->setFileInfo (fileInfo);
@@ -1143,7 +1156,7 @@
 	}
 
 	m_objects.removeAt (idx);
-	obj->setDocument (null);
+	obj->setDocument (LDDocumentPtr());
 }
 
 // =============================================================================
@@ -1188,9 +1201,11 @@
 //
 bool safeToCloseAll()
 {
-	for (LDDocument* f : g_loadedFiles)
+	for (LDDocumentPtr f : LDDocument::explicitDocuments())
+	{
 		if (not f->isSafeToClose())
 			return false;
+	}
 
 	return true;
 }
@@ -1211,7 +1226,7 @@
 
 	removeKnownVerticesOf (m_objects[idx]);
 	m_objects[idx]->deselect();
-	m_objects[idx]->setDocument (null);
+	m_objects[idx]->setDocument (LDDocumentPtr());
 	obj->setDocument (this);
 	addKnownVerticesOf (obj);
 	g_win->R()->compileObject (obj);
@@ -1222,16 +1237,7 @@
 //
 // Close all documents we don't need anymore
 //
-void LDDocument::closeUnused()
-{
-	for (int i = 0; i < g_loadedFiles.size(); ++i)
-	{
-		LDDocument* file = g_loadedFiles[i];
-
-		if (file->isImplicit() && file->references().isEmpty())
-			delete g_loadedFiles[i--];
-	}
-}
+void LDDocument::closeUnused() {}
 
 // =============================================================================
 //
@@ -1254,7 +1260,7 @@
 //
 bool LDDocument::hasUnsavedChanges() const
 {
-	return !isImplicit() && history()->position() != savePosition();
+	return not isImplicit() && history()->position() != savePosition();
 }
 
 // =============================================================================
@@ -1277,10 +1283,9 @@
 	if (not m_needsReCache)
 		return;
 
-	LDObjectList objs = inlineContents (true, true);
 	m_storedVertices.clear();
 
-	for (LDObjectPtr obj : objs)
+	for (LDObjectPtr obj : inlineContents (true, true))
 	{
 		assert (obj->type() != LDObject::ESubfile);
 		LDPolygon* data = obj->getPolygon();
@@ -1293,8 +1298,6 @@
 
 		for (int i = 0; i < obj->numVertices(); ++i)
 			m_storedVertices << obj->vertex (i);
-
-		obj->destroy();
 	}
 
 	removeDuplicates (m_storedVertices);
@@ -1339,10 +1342,7 @@
 		// just add it into the objects normally. Yay, recursion!
 		if (deep == true && obj->type() == LDObject::ESubfile)
 		{
-			LDSubfilePtr ref = obj.staticCast<LDSubfile>();
-			LDObjectList otherobjs = ref->inlineContents (deep, renderinline);
-
-			for (LDObjectPtr otherobj : otherobjs)
+			for (LDObjectPtr otherobj : obj.staticCast<LDSubfile>()->inlineContents (deep, renderinline))
 				objs << otherobj;
 		}
 		else
@@ -1354,9 +1354,9 @@
 
 // =============================================================================
 //
-LDDocument* LDDocument::current()
+LDDocumentPtr LDDocument::current()
 {
-	return m_curdoc;
+	return g_currentDocument;
 }
 
 // =============================================================================
@@ -1365,14 +1365,14 @@
 //
 // TODO: f can be temporarily null. This probably should not be the case.
 // =============================================================================
-void LDDocument::setCurrent (LDDocument* f)
+void LDDocument::setCurrent (LDDocumentPtr f)
 {
 	// Implicit files were loaded for caching purposes and must never be set
 	// current.
-	if (f && f->isImplicit())
+	if (f != null && f->isImplicit())
 		return;
 
-	m_curdoc = f;
+	g_currentDocument = f;
 
 	if (g_win && f)
 	{
@@ -1390,15 +1390,7 @@
 //
 int LDDocument::countExplicitFiles()
 {
-	int count = 0;
-
-	for (LDDocument* f : g_loadedFiles)
-	{
-		if (not f->isImplicit())
-			++count;
-	}
-
-	return count;
+	return g_explicitDocuments.size();
 }
 
 // =============================================================================
@@ -1407,12 +1399,12 @@
 // =============================================================================
 void LDDocument::closeInitialFile()
 {
-	if (countExplicitFiles() == 2 &&
-		g_loadedFiles[0]->name().isEmpty() &&
-		not g_loadedFiles[1]->name().isEmpty() &&
-		not g_loadedFiles[0]->hasUnsavedChanges())
+	if (g_explicitDocuments.size() == 2 &&
+		g_explicitDocuments[0]->name().isEmpty() &&
+		not g_explicitDocuments[1]->name().isEmpty() &&
+		not g_explicitDocuments[0]->hasUnsavedChanges())
 	{
-		delete g_loadedFiles[0];
+		g_explicitDocuments[0]->dismiss();
 	}
 }
 
@@ -1423,9 +1415,6 @@
 	if (g_logoedStud && g_logoedStud2)
 		return;
 
-	delete g_logoedStud;
-	delete g_logoedStud2;
-
 	g_logoedStud = openDocument ("stud-logo.dat", true, true);
 	g_logoedStud2 = openDocument ("stud2-logo.dat", true, true);
 
@@ -1439,7 +1428,7 @@
 	if (obj->isSelected())
 		return;
 
-	assert (obj->document() == this);
+	assert (obj->document() == self());
 	m_sel << obj;
 	g_win->R()->compileObject (obj);
 	obj->setSelected (true);
@@ -1452,7 +1441,7 @@
 	if (not obj->isSelected())
 		return;
 
-	assert (obj->document() == this);
+	assert (obj->document() == self());
 	m_sel.removeOne (obj);
 	g_win->R()->compileObject (obj);
 	obj->setSelected (false);
@@ -1502,23 +1491,6 @@
 
 // =============================================================================
 //
-void LDDocument::addReference (LDDocumentPointer* ptr)
-{
-	m_references << ptr;
-}
-
-// =============================================================================
-//
-void LDDocument::removeReference (LDDocumentPointer* ptr)
-{
-	m_references.removeOne (ptr);
-
-	if (references().isEmpty())
-		invokeLater (closeUnused);
-}
-
-// =============================================================================
-//
 QList<Vertex> LDDocument::inlineVertices()
 {
 	initializeCachedData();
--- a/src/ldDocument.h	Sun Jun 01 03:15:36 2014 +0300
+++ b/src/ldDocument.h	Mon Jun 02 12:50:40 2014 +0300
@@ -25,7 +25,6 @@
 
 class History;
 class OpenProgressDialog;
-class LDDocumentPointer;
 struct LDGLData;
 class GLCompiler;
 
@@ -51,12 +50,11 @@
 Q_DECLARE_FLAGS (LDDocumentFlags, LDDocumentFlag)
 Q_DECLARE_OPERATORS_FOR_FLAGS (LDDocumentFlags)
 
-// =============================================================================
 //
 // This class stores a document either as a editable file for the user or for
-// subfile caching. Its methods handle file input and output.
+// subfile caching.
 //
-// A file is implicit when they are opened automatically for caching purposes
+// A document is implicit when they are opened automatically for caching purposes
 // and are hidden from the user. User-opened files are explicit (not implicit).
 //
 // The default name is a placeholder, initially suggested name for a file. The
@@ -65,26 +63,24 @@
 class LDDocument : public QObject
 {
 	public:
-		using ReferenceList = QList<LDDocumentPointer*>;
 		using KnownVertexMap = QMap<Vertex, int>;
 
-		Q_OBJECT
-		PROPERTY (public,	String,		name,			setName,			STOCK_WRITE)
-		PROPERTY (private,	LDObjectList,	objects, 		setObjects,			STOCK_WRITE)
-		PROPERTY (private,	LDObjectList,	cache, 			setCache,			STOCK_WRITE)
-		PROPERTY (private,	History*,		history,		setHistory,			STOCK_WRITE)
-		PROPERTY (private,	KnownVertexMap,	vertices,		setVertices,		STOCK_WRITE)
-		PROPERTY (private,	ReferenceList,	references,		setReferences,		STOCK_WRITE)
-		PROPERTY (public,	String,		fullPath,		setFullPath,		STOCK_WRITE)
-		PROPERTY (public,	String,		defaultName,	setDefaultName,		STOCK_WRITE)
-		PROPERTY (public,	bool,			isImplicit,		setImplicit,		STOCK_WRITE)
-		PROPERTY (public,	long,			savePosition,	setSavePosition,	STOCK_WRITE)
-		PROPERTY (public,	int,			tabIndex,		setTabIndex,		STOCK_WRITE)
-		PROPERTY (public,	QList<LDPolygon>,	polygonData,	setPolygonData,	STOCK_WRITE)
-		PROPERTY (private,	LDDocumentFlags,	flags,			setFlags,		STOCK_WRITE)
+		PROPERTY (public,	String,				name,			setName,			STOCK_WRITE)
+		PROPERTY (private,	LDObjectList,		objects, 		setObjects,			STOCK_WRITE)
+		PROPERTY (private,	LDObjectList,		cache, 			setCache,			STOCK_WRITE)
+		PROPERTY (private,	History*,			history,		setHistory,			STOCK_WRITE)
+		PROPERTY (private,	KnownVertexMap,		vertices,		setVertices,		STOCK_WRITE)
+		PROPERTY (public,	String,				fullPath,		setFullPath,		STOCK_WRITE)
+		PROPERTY (public,	String,				defaultName,	setDefaultName,		STOCK_WRITE)
+		PROPERTY (public,	bool,				isImplicit,		setImplicit,		CUSTOM_WRITE)
+		PROPERTY (public,	long,				savePosition,	setSavePosition,	STOCK_WRITE)
+		PROPERTY (public,	int,				tabIndex,		setTabIndex,		STOCK_WRITE)
+		PROPERTY (public,	QList<LDPolygon>,	polygonData,	setPolygonData,		STOCK_WRITE)
+		PROPERTY (private,	LDDocumentFlags,	flags,			setFlags,			STOCK_WRITE)
+		PROPERTY (private,	LDDocumentWeakPtr,	self,			setSelf,			STOCK_WRITE)
 
 	public:
-		LDDocument();
+		LDDocument(LDDocumentPtr* selfptr);
 		~LDDocument();
 
 		int addObject (LDObjectPtr obj); // Adds an object to this file at the end of the file.
@@ -103,13 +99,12 @@
 		void swapObjects (LDObjectPtr one, LDObjectPtr other);
 		bool isSafeToClose(); // Perform safety checks. Do this before closing any files!
 		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(LDObjectPtr obj);
 		void removeKnownVerticesOf (LDObjectPtr sub);
 		QList<Vertex> inlineVertices();
+		void clear();
 
 		inline LDDocument& operator<< (LDObjectPtr obj)
 		{
@@ -142,14 +137,21 @@
 			*history() << entry;
 		}
 
+		inline void dismiss()
+		{
+			setImplicit (true);
+		}
+
 		static void closeUnused();
-		static LDDocument* current();
-		static void setCurrent (LDDocument* f);
+		static LDDocumentPtr current();
+		static void setCurrent (LDDocumentPtr f);
 		static void closeInitialFile();
 		static int countExplicitFiles();
+		static LDDocumentPtr createNew();
 
 		// Turns a full path into a relative path
 		static String shortenName (String a);
+		static QList<LDDocumentPtr> const& explicitDocuments();
 
 	protected:
 		void addToSelection (LDObjectPtr obj);
@@ -172,13 +174,11 @@
 		// stored polygon data and re-builds it.
 		bool					m_needsReCache;
 
-		static LDDocument*		m_curdoc;
-
 		void addKnownVertexReference (const Vertex& a);
 		void removeKnownVertexReference (const Vertex& a);
 };
 
-inline LDDocument* getCurrentDocument()
+inline LDDocumentPtr getCurrentDocument()
 {
 	return LDDocument::current();
 }
@@ -190,11 +190,11 @@
 void openMainFile (String path);
 
 // Finds an OpenFile by name or null if not open
-LDDocument* findDocument (String name);
+LDDocumentPtr findDocument (String name);
 
 // Opens the given file and parses the LDraw code within. Returns a pointer
 // to the opened file or null on error.
-LDDocument* openDocument (String path, bool search, bool implicit);
+LDDocumentPtr openDocument (String path, bool search, bool implicit, LDDocumentPtr fileToOverride = LDDocumentPtr());
 
 // Opens the given file and returns a pointer to it, potentially looking in /parts and /p
 QFile* openLDrawFile (String relpath, bool subdirs, String* pathpointer = null);
@@ -207,7 +207,7 @@
 
 // Retrieves the pointer to the given document by file name. Document is loaded
 // from file if necessary. Can return null if neither succeeds.
-LDDocument* getDocument (String filename);
+LDDocumentPtr getDocument (String filename);
 
 // Re-caches all subfiles.
 void reloadAllSubfiles();
@@ -217,8 +217,6 @@
 
 LDObjectList loadFileContents (QFile* f, int* numWarnings, bool* ok = null);
 
-extern QList<LDDocument*> g_loadedFiles;
-
 inline const LDObjectList& selection()
 {
 	return getCurrentDocument()->getSelection();
@@ -229,8 +227,6 @@
 String basename (String path);
 String dirname (String path);
 
-extern QList<LDDocument*> g_loadedFiles; // Vector of all currently opened files.
-
 // =============================================================================
 //
 // LDFileLoader
--- a/src/ldObject.cc	Sun Jun 01 03:15:36 2014 +0300
+++ b/src/ldObject.cc	Mon Jun 02 12:50:40 2014 +0300
@@ -32,7 +32,7 @@
 CFGENTRY (Int, defaultLicense, 0);
 
 // List of all LDObjects
-static QMap<long, LDObjectWeakPtr>	g_allObjects;
+QMap<long, LDObjectWeakPtr>	g_allObjects;
 static int32						g_idcursor = 1; // 0 shalt be null
 static constexpr int32				g_maxID = (1 << 24);
 
@@ -47,7 +47,6 @@
 	m_isHidden (false),
 	m_isSelected (false),
 	m_isDestructed (false),
-	m_document (null),
 	qObjListEntry (null)
 {
 	*selfptr = LDObjectPtr (this, [](LDObject* obj){ obj->finalDelete(); });
@@ -242,7 +241,7 @@
 	assert (idx != -1);
 
 	// Replace the instance of the old object with the new object
-	document()->setObject (idx, other);
+	document().toStrongRef()->setObject (idx, other);
 
 	// Remove the old object
 	destroy();
@@ -253,7 +252,7 @@
 void LDObject::swap (LDObjectPtr other)
 {
 	assert (document() == other->document());
-	document()->swapObjects (self(), other);
+	document().toStrongRef()->swapObjects (self(), other);
 }
 
 // =============================================================================
@@ -302,8 +301,8 @@
 		deselect();
 
 	// If this object was associated to a file, remove it off it now
-	if (document())
-		document()->forgetObject (self());
+	if (document() != null)
+		document().toStrongRef()->forgetObject (self());
 
 	// Delete the GL lists
 	g_win->R()->forgetObject (self());
@@ -424,8 +423,8 @@
 {
 	assert (document() != null);
 
-	for (int i = 0; i < document()->getObjectCount(); ++i)
-		if (document()->getObject (i) == this)
+	for (int i = 0; i < document().toStrongRef()->getObjectCount(); ++i)
+		if (document().toStrongRef()->getObject (i) == this)
 			return i;
 
 	return -1;
@@ -443,7 +442,7 @@
 	const long end = up ? objs.size() : -1;
 	const long incr = up ? 1 : -1;
 	LDObjectList objsToCompile;
-	LDDocument* file = objs[0]->document();
+	LDDocumentPtr file = objs[0]->document();
 
 	for (long i = start; i != end; i += incr)
 	{
@@ -539,10 +538,10 @@
 	long idx = lineNumber();
 	assert (idx != -1);
 
-	if (idx == (long) document()->getObjectCount() - 1)
+	if (idx == (long) document().toStrongRef()->getObjectCount() - 1)
 		return LDObjectPtr();
 
-	return document()->getObject (idx + 1);
+	return document().toStrongRef()->getObject (idx + 1);
 }
 
 // =============================================================================
@@ -555,7 +554,7 @@
 	if (idx == 0)
 		return LDObjectPtr();
 
-	return document()->getObject (idx - 1);
+	return document().toStrongRef()->getObject (idx - 1);
 }
 
 // =============================================================================
@@ -654,6 +653,9 @@
 //
 void LDSubfile::invert()
 {
+	if (document() == null)
+		return;
+
 	// Check whether subfile is flat
 	int axisSet = (1 << X) | (1 << Y) | (1 << Z);
 	LDObjectList objs = inlineContents (true, false);
@@ -713,7 +715,7 @@
 	}
 
 	// Not inverted, thus prefix it with a new invertnext.
-	document()->insertObj (idx, spawn<LDBFC> (LDBFC::InvertNext));
+	document().toStrongRef()->insertObj (idx, spawn<LDBFC> (LDBFC::InvertNext));
 }
 
 // =============================================================================
@@ -798,7 +800,7 @@
 
 		if (before != after)
 		{
-			obj->document()->addToHistory (new EditHistory (idx, before, after));
+			obj->document().toStrongRef()->addToHistory (new EditHistory (idx, before, after));
 			g_win->R()->compileObject (obj);
 		}
 	}
@@ -825,7 +827,7 @@
 void LDObject::setVertex (int i, const Vertex& vert)
 {
 	if (document() != null)
-		document()->vertexChanged (*m_coords[i], vert);
+		document().toStrongRef()->vertexChanged (*m_coords[i], vert);
 
 	changeProperty (self(), &m_coords[i], LDSharedVertex::getSharedVertex (vert));
 }
@@ -837,12 +839,12 @@
 	LDObjectPtr ref = linkPointer().toStrongRef();
 
 	if (ref->document() != null)
-		ref->document()->removeKnownVerticesOf (ref);
+		ref->document().toStrongRef()->removeKnownVerticesOf (ref);
 
 	changeProperty (ref, &m_position, LDSharedVertex::getSharedVertex (a));
 
 	if (ref->document() != null)
-		ref->document()->addKnownVerticesOf (ref);
+		ref->document().toStrongRef()->addKnownVerticesOf (ref);
 }
 
 // =============================================================================
@@ -852,12 +854,12 @@
 	LDObjectPtr ref = linkPointer().toStrongRef();
 
 	if (ref->document() != null)
-		ref->document()->removeKnownVerticesOf (ref);
+		ref->document().toStrongRef()->removeKnownVerticesOf (ref);
 
 	changeProperty (ref, &m_transform, val);
 
 	if (ref->document() != null)
-		ref->document()->addKnownVerticesOf (ref);
+		ref->document().toStrongRef()->addKnownVerticesOf (ref);
 }
 
 // =============================================================================
@@ -903,7 +905,7 @@
 void LDObject::select()
 {
 	assert (document() != null);
-	document()->addToSelection (self());
+	document().toStrongRef()->addToSelection (self());
 
 	// If this object is inverted with INVERTNEXT, pick the INVERTNEXT as well.
 	LDBFCPtr invertnext;
@@ -917,7 +919,7 @@
 void LDObject::deselect()
 {
 	assert (document() != null);
-	document()->removeFromSelection (self());
+	document().toStrongRef()->removeFromSelection (self());
 
 	// If this object is inverted with INVERTNEXT, deselect the INVERTNEXT as well.
 	LDBFCPtr invertnext;
@@ -956,10 +958,10 @@
 
 // =============================================================================
 //
-void LDSubfile::setFileInfo (const LDDocumentPointer& a)
+void LDSubfile::setFileInfo (const LDDocumentPtr& a)
 {
 	if (document() != null)
-		document()->removeKnownVerticesOf (self());
+		document().toStrongRef()->removeKnownVerticesOf (self());
 
 	m_fileInfo = a;
 
@@ -974,5 +976,5 @@
 	}
 
 	if (document() != null)
-		document()->addKnownVerticesOf (self());
+		document().toStrongRef()->addKnownVerticesOf (self());
 };
--- a/src/ldObject.h	Sun Jun 01 03:15:36 2014 +0300
+++ b/src/ldObject.h	Mon Jun 02 12:50:40 2014 +0300
@@ -73,7 +73,7 @@
 	PROPERTY (public,		bool,				isSelected,		setSelected,	STOCK_WRITE)
 	PROPERTY (public,		bool,				isDestructed,	setDestructed,	STOCK_WRITE)
 	PROPERTY (public,		LDObjectWeakPtr,	parent,			setParent,		STOCK_WRITE)
-	PROPERTY (public,		LDDocument*,		document,		setDocument,	STOCK_WRITE)
+	PROPERTY (public,		LDDocumentWeakPtr,	document,		setDocument,	STOCK_WRITE)
 	PROPERTY (private,		int32,				id,				setID,			STOCK_WRITE)
 	PROPERTY (public,		int,				color,			setColor,		CUSTOM_WRITE)
 	PROPERTY (private,		QColor,				randomColor,	setRandomColor,	STOCK_WRITE)
@@ -447,7 +447,7 @@
 	LDOBJ_COLORED
 	LDOBJ_SCEMANTIC
 	LDOBJ_HAS_MATRIX
-	PROPERTY (public, LDDocumentPointer, fileInfo, setFileInfo, CUSTOM_WRITE)
+	PROPERTY (public, LDDocumentPtr, fileInfo, setFileInfo, CUSTOM_WRITE)
 
 	public:
 		enum InlineFlag
--- a/src/main.cc	Sun Jun 01 03:15:36 2014 +0300
+++ b/src/main.cc	Mon Jun 02 12:50:40 2014 +0300
@@ -34,7 +34,6 @@
 #include "dialogs.h"
 #include "crashCatcher.h"
 
-QList<LDDocument*> g_loadedFiles;
 MainWindow* g_win = null;
 static String g_versionString, g_fullVersionString;
 
@@ -51,7 +50,6 @@
 	app.setOrganizationName (APPNAME);
 	app.setApplicationName (APPNAME);
 	initCrashCatcher();
-	LDDocument::setCurrent (null);
 
 	// Load or create the configuration
 	if (not Config::load())
--- a/src/mainWindow.cc	Sun Jun 01 03:15:36 2014 +0300
+++ b/src/mainWindow.cc	Mon Jun 02 12:50:40 2014 +0300
@@ -724,7 +724,7 @@
 
 // =============================================================================
 //
-bool MainWindow::save (LDDocument* doc, bool saveAs)
+bool MainWindow::save (LDDocumentPtr doc, bool saveAs)
 {
 	String path = doc->fullPath();
 
@@ -889,12 +889,8 @@
 	while (m_tabs->count() > 0)
 		m_tabs->removeTab (0);
 
-	for (LDDocument* f : g_loadedFiles)
+	for (LDDocumentPtr f : LDDocument::explicitDocuments())
 	{
-		// Don't list implicit files unless explicitly desired.
-		if (f->isImplicit() && not cfg::listImplicitFiles)
-			continue;
-
 		// Add an item to the list for this file and store the tab index
 		// in the document so we can find documents by tab index.
 		f->setTabIndex (m_tabs->addTab (""));
@@ -906,7 +902,7 @@
 
 // =============================================================================
 //
-void MainWindow::updateDocumentListItem (LDDocument* doc)
+void MainWindow::updateDocumentListItem (LDDocumentPtr doc)
 {
 	bool oldUpdatingTabs = m_updatingTabs;
 	m_updatingTabs = true;
@@ -941,11 +937,11 @@
 	if (m_updatingTabs)
 		return;
 
-	LDDocument* f = null;
+	LDDocumentPtr f;
 	int tabIndex = m_tabs->currentIndex();
 
 	// Find the file pointer of the item that was selected.
-	for (LDDocument* it : g_loadedFiles)
+	for (LDDocumentPtr it : LDDocument::explicitDocuments())
 	{
 		if (it->tabIndex() == tabIndex)
 		{
@@ -968,7 +964,7 @@
 {
 #if 0
 	ui->objectList->clear();
-	LDDocument* f = getCurrentDocument();
+	LDDocumentPtr f = getCurrentDocument();
 
 for (LDObjectPtr obj : *f)
 		ui->objectList->addItem (obj->qObjListEntry);
--- a/src/mainWindow.h	Sun Jun 01 03:15:36 2014 +0300
+++ b/src/mainWindow.h	Mon Jun 02 12:50:40 2014 +0300
@@ -129,7 +129,7 @@
 
 		//! Updates the document tab for \c doc. If no such tab exists, the
 		//! document list is rebuilt instead.
-		void updateDocumentListItem (LDDocument* doc);
+		void updateDocumentListItem (LDDocumentPtr doc);
 
 		//! \returns the uniform selected color (i.e. 4 if everything selected is
 		//! red), -1 if there is no such consensus.
@@ -158,7 +158,7 @@
 		//! \param doc the document to save
 		//! \param saveAs if true, always ask for a file path
 		//! \returns whether the save was successful
-		bool save (LDDocument* doc, bool saveAs);
+		bool save (LDDocumentPtr doc, bool saveAs);
 
 		//! Updates various actions, undo/redo are set enabled/disabled where
 		//! appropriate, togglable actions are updated based on configuration,
--- a/src/misc/documentPointer.cc	Sun Jun 01 03:15:36 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- *  LDForge: LDraw parts authoring CAD
- *  Copyright (C) 2013, 2014 Santeri Piippo
- *
- *  This program is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "documentPointer.h"
-#include "../ldDocument.h"
-#include "../miscallenous.h"
-
-LDDocumentPointer::LDDocumentPointer()  : m_pointer (null) {}
-
-// =============================================================================
-//
-LDDocumentPointer::LDDocumentPointer (LDDocument* ptr) :
-	m_pointer (ptr)
-{
-	addReference ();
-}
-
-// =============================================================================
-//
-LDDocumentPointer::LDDocumentPointer (const LDDocumentPointer& other) :
-	m_pointer (other.pointer())
-{
-	addReference ();
-}
-
-// =============================================================================
-//
-LDDocumentPointer::~LDDocumentPointer()
-{
-	removeReference();
-}
-
-// =============================================================================
-//
-void LDDocumentPointer::addReference()
-{
-	if (pointer() != null)
-		pointer()->addReference (this);
-}
-
-// =============================================================================
-//
-void LDDocumentPointer::removeReference()
-{
-	if (pointer() != null)
-		pointer()->removeReference (this);
-}
-
-// =============================================================================
-//
-LDDocumentPointer& LDDocumentPointer::operator= (LDDocument* ptr)
-{
-	if (ptr != pointer())
-	{
-		removeReference();
-		setPointer (ptr);
-		addReference();
-	}
-
-	return *this;
-}
\ No newline at end of file
--- a/src/misc/documentPointer.h	Sun Jun 01 03:15:36 2014 +0300
+++ b/src/misc/documentPointer.h	Mon Jun 02 12:50:40 2014 +0300
@@ -1,74 +0,0 @@
-/*
- *  LDForge: LDraw parts authoring CAD
- *  Copyright (C) 2013, 2014 Santeri Piippo
- *
- *  This program is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#pragma once
-
-#include "../main.h"
-
-class LDSubfile;
-class LDDocument;
-
-//!
-//! \brief A reference-counting pointer to LDDocument.
-//!
-//! The LDDocumentPointer class defines a reference-counting pointer which
-//! points to LDDocument.
-//!
-class LDDocumentPointer
-{
-	PROPERTY (private, LDDocument*, pointer, setPointer, STOCK_WRITE)
-
-	public:
-		//! Constructs a null LDDocumentPointer
-		LDDocumentPointer();
-
-		//! Constructs a document pointer with the given pointer
-		LDDocumentPointer (LDDocument* ptr);
-
-		//! Copy-constructs a LDDocumentPointer.
-		LDDocumentPointer (const LDDocumentPointer& other);
-
-		//! Destructs the pointer.
-		~LDDocumentPointer();
-
-		//! \param ptr the new pointer to change to.
-		LDDocumentPointer& operator= (LDDocument* ptr);
-
-		//! Copy operator.
-		//! \param other the pointer whose internal pointer to copy.
-		inline LDDocumentPointer& operator= (LDDocumentPointer& other)
-		{
-			return operator= (other.pointer());
-		}
-
-		//! Operator overload for a->b support.
-		inline LDDocument* operator->() const
-		{
-			return pointer();
-		}
-
-		//! Cast operator overload
-		inline operator LDDocument*() const
-		{
-			return pointer();
-		}
-
-	private:
-		void addReference();
-		void removeReference();
-};
--- a/src/miscallenous.cc	Sun Jun 01 03:15:36 2014 +0300
+++ b/src/miscallenous.cc	Mon Jun 02 12:50:40 2014 +0300
@@ -25,7 +25,6 @@
 #include "dialogs.h"
 #include "ldDocument.h"
 #include "ui_rotpoint.h"
-#include "misc/documentPointer.cc"
 #include "misc/ringFinder.cc"
 #include "misc/invokeLater.cc"
 
--- a/src/partDownloader.cc	Sun Jun 01 03:15:36 2014 +0300
+++ b/src/partDownloader.cc	Mon Jun 02 12:50:40 2014 +0300
@@ -213,7 +213,7 @@
 	elif (btn == getButton (Download))
 	{
 		QString dest = interface()->fname->text();
-		setPrimaryFile (null);
+		setPrimaryFile (LDDocumentPtr());
 		setAborted (false);
 
 		if (getSource() == CustomURL)
@@ -446,7 +446,7 @@
 	}
 
 	// Try to load this file now.
-	LDDocument* f = openDocument (filePath(), false, not isPrimary());
+	LDDocumentPtr f = openDocument (filePath(), false, not isPrimary());
 
 	if (f == null)
 		return;
--- a/src/partDownloader.h	Sun Jun 01 03:15:36 2014 +0300
+++ b/src/partDownloader.h	Mon Jun 02 12:50:40 2014 +0300
@@ -20,6 +20,7 @@
 #include <QDialog>
 #include "main.h"
 #include "basics.h"
+#include "ldDocument.h"
 
 class LDDocument;
 class QFile;
@@ -57,7 +58,7 @@
 		using RequestList = QList<PartDownloadRequest*>;
 
 		Q_OBJECT
-		PROPERTY (public,	LDDocument*, 		primaryFile,		setPrimaryFile,		STOCK_WRITE)
+		PROPERTY (public,	LDDocumentPtr, 		primaryFile,		setPrimaryFile,		STOCK_WRITE)
 		PROPERTY (public,	bool,				isAborted,			setAborted,			STOCK_WRITE)
 		PROPERTY (private,	Ui_DownloadFrom*,	interface,			setInterface,		STOCK_WRITE)
 		PROPERTY (private,	QStringList,		filesToDownload,	setFilesToDownload,	STOCK_WRITE)
--- a/src/primitives.cc	Sun Jun 01 03:15:36 2014 +0300
+++ b/src/primitives.cc	Mon Jun 02 12:50:40 2014 +0300
@@ -579,7 +579,7 @@
 
 // =============================================================================
 //
-LDDocument* generatePrimitive (PrimitiveType type, int segs, int divs, int num)
+LDDocumentPtr generatePrimitive (PrimitiveType type, int segs, int divs, int num)
 {
 	// Make the description
 	QString frac = QString::number ((float) segs / divs);
@@ -605,7 +605,7 @@
 	if (divs == g_hires)
 		descr.insert (0, "Hi-Res ");
 
-	LDDocument* f = new LDDocument;
+	LDDocumentPtr f = LDDocument::createNew();
 	f->setDefaultName (name);
 
 	QString author = APPNAME;
@@ -635,10 +635,10 @@
 
 // =============================================================================
 //
-LDDocument* getPrimitive (PrimitiveType type, int segs, int divs, int num)
+LDDocumentPtr getPrimitive (PrimitiveType type, int segs, int divs, int num)
 {
 	QString name = radialFileName (type, segs, divs, num);
-	LDDocument* f = getDocument (name);
+	LDDocumentPtr f = getDocument (name);
 
 	if (f != null)
 		return f;
@@ -694,8 +694,7 @@
 		dlg->ui->rb_ndisc->isChecked()    ? DiscNeg :
 		dlg->ui->rb_ring->isChecked()     ? Ring : Cone;
 
-	LDDocument* f = generatePrimitive (type, segs, divs, num);
-
+	LDDocumentPtr f = generatePrimitive (type, segs, divs, num);
+	f->setImplicit (false);
 	g_win->save (f, false);
-	delete f;
 }
--- a/src/primitives.h	Sun Jun 01 03:15:36 2014 +0300
+++ b/src/primitives.h	Mon Jun 02 12:50:40 2014 +0300
@@ -121,10 +121,10 @@
 };
 
 void makeCircle (int segs, int divs, double radius, QList<QLineF>& lines);
-LDDocument* generatePrimitive (PrimitiveType type, int segs, int divs, int num);
+LDDocumentPtr generatePrimitive (PrimitiveType type, int segs, int divs, int num);
 
 // Gets a primitive by the given specs. If the primitive cannot be found, it will
 // be automatically generated.
-LDDocument* getPrimitive (PrimitiveType type, int segs, int divs, int num);
+LDDocumentPtr getPrimitive (PrimitiveType type, int segs, int divs, int num);
 
 QString radialFileName (PrimitiveType type, int segs, int divs, int num);

mercurial