- corrected history behavior. LDObject::clone() is now off-limits, createCopy() must be used instead. LDObject::deleteSelf() must be used to delete LDObjects (destructor is protected now)

Wed, 18 Dec 2013 17:44:31 +0200

author
Santeri Piippo <crimsondusk64@gmail.com>
date
Wed, 18 Dec 2013 17:44:31 +0200
changeset 560
39085791128f
parent 559
5a31f6c14451
child 561
1d90296ad3fc

- corrected history behavior. LDObject::clone() is now off-limits, createCopy() must be used instead. LDObject::deleteSelf() must be used to delete LDObjects (destructor is protected now)

src/addObjectDialog.cc file | annotate | diff | comparison | revisions
src/document.cc file | annotate | diff | comparison | revisions
src/extprogs.cc file | annotate | diff | comparison | revisions
src/gldraw.cc file | annotate | diff | comparison | revisions
src/gui.cc file | annotate | diff | comparison | revisions
src/gui_editactions.cc file | annotate | diff | comparison | revisions
src/history.cc file | annotate | diff | comparison | revisions
src/history.h file | annotate | diff | comparison | revisions
src/ldtypes.cc file | annotate | diff | comparison | revisions
src/ldtypes.h file | annotate | diff | comparison | revisions
src/main.h file | annotate | diff | comparison | revisions
src/types.cc file | annotate | diff | comparison | revisions
--- a/src/addObjectDialog.cc	Wed Dec 18 17:03:35 2013 +0200
+++ b/src/addObjectDialog.cc	Wed Dec 18 17:44:31 2013 +0200
@@ -243,7 +243,7 @@
 	setWindowTitle (fmt (tr ("Edit %1"), typeName));
 
 	setWindowIcon (icon);
-	delete defaults;
+	defaults->deleteSelf();
 }
 
 // =============================================================================
--- a/src/document.cc	Wed Dec 18 17:03:35 2013 +0200
+++ b/src/document.cc	Wed Dec 18 17:44:31 2013 +0200
@@ -125,11 +125,11 @@
 LDDocument::~LDDocument()
 {	// Clear everything from the model
 	for (LDObject* obj : getObjects())
-		delete obj;
+		obj->deleteSelf();
 
 	// Clear the cache as well
 	for (LDObject* obj : getCache())
-		delete obj;
+		obj->deleteSelf();
 
 	delete m_History;
 
@@ -284,7 +284,7 @@
 {	// User wishes to abort, so stop here now.
 	if (isAborted())
 	{	for (LDObject* obj : m_Objects)
-			delete obj;
+			obj->deleteSelf();
 
 		m_Objects.clear();
 		setDone (true);
@@ -870,6 +870,11 @@
 	if (obj->getType() == LDObject::Vertex)
 		m_Vertices << obj;
 
+#ifdef DEBUG
+	if (!isImplicit())
+		dlog ("Added object #%1\n", obj->getID());
+#endif
+
 	obj->setFile (this);
 	return getObjectCount() - 1;
 }
@@ -877,7 +882,7 @@
 // =============================================================================
 // -----------------------------------------------------------------------------
 void LDDocument::addObjects (const QList<LDObject*> objs)
-{	for (LDObject * obj : objs)
+{	for (LDObject* obj : objs)
 		if (obj)
 			addObject (obj);
 }
@@ -894,6 +899,8 @@
 // -----------------------------------------------------------------------------
 void LDDocument::forgetObject (LDObject* obj)
 {	int idx = obj->getIndex();
+	assert (m_Objects[idx] == obj);
+	dlog ("id: %1, type: %2, code: %3", obj->getID(), obj->getType(), obj->raw());
 	getHistory()->add (new DelHistory (idx, obj));
 	m_Objects.removeAt (idx);
 	obj->setFile (null);
@@ -1015,9 +1022,8 @@
 	if (gl_logostuds && (flags & LDSubfile::RendererInline))
 	{	if (getName() == "stud.dat" && g_logoedStud)
 			return g_logoedStud->inlineContents (flags);
-
 		elif (getName() == "stud2.dat" && g_logoedStud2)
-		return g_logoedStud2->inlineContents (flags);
+			return g_logoedStud2->inlineContents (flags);
 	}
 
 	QList<LDObject*> objs, objcache;
@@ -1025,10 +1031,10 @@
 	bool deep = flags & LDSubfile::DeepInline,
 		 doCache = flags & LDSubfile::CacheInline;
 
-	// If we have this cached, just clone that
+	// If we have this cached, just create a copy of that
 	if (deep && getCache().size())
 	{	for (LDObject* obj : getCache())
-			objs << obj->clone();
+			objs << obj->createCopy();
 	}
 	else
 	{	if (!deep)
@@ -1049,19 +1055,19 @@
 				// flag when recursing deeper in hierarchy.
 				QList<LDObject*> otherobjs = ref->inlineContents (flags & ~ (LDSubfile::CacheInline));
 
-			for (LDObject * otherobj : otherobjs)
+				for (LDObject* otherobj : otherobjs)
 				{	// Cache this object, if desired
 					if (doCache)
-						objcache << otherobj->clone();
+						objcache << otherobj->createCopy();
 
 					objs << otherobj;
 				}
 			}
 			else
 			{	if (doCache)
-					objcache << obj->clone();
+					objcache << obj->createCopy();
 
-				objs << obj->clone();
+				objs << obj->createCopy();
 			}
 		}
 
--- a/src/extprogs.cc	Wed Dec 18 17:03:35 2013 +0200
+++ b/src/extprogs.cc	Wed Dec 18 17:44:31 2013 +0200
@@ -157,7 +157,7 @@
 			writeObjects (objs, f);
 
 			for (LDObject* obj : objs)
-				delete obj;
+				obj->deleteSelf();
 		}
 		else
 			f.write (obj->raw() + "\r\n");
@@ -282,7 +282,7 @@
 
 	for (LDObject * obj : objs)
 	{	if (!obj->isScemantic())
-		{	delete obj;
+		{	obj->deleteSelf();
 			continue;
 		}
 
--- a/src/gldraw.cc	Wed Dec 18 17:03:35 2013 +0200
+++ b/src/gldraw.cc	Wed Dec 18 17:44:31 2013 +0200
@@ -858,12 +858,11 @@
 
 	switch (obj->getType())
 	{	case LDObject::Line:
-			compileSubObject (obj, GL_LINES);
-			break;
+		{	compileSubObject (obj, GL_LINES);
+		} break;
 
 		case LDObject::CondLine:
-
-			// Draw conditional lines with a dash pattern - however, use a full
+		{	// Draw conditional lines with a dash pattern - however, use a full
 			// line when drawing a pick list to make selecting them easier.
 			if (list != GL::PickList)
 			{	glLineStipple (1, 0x6666);
@@ -873,15 +872,15 @@
 			compileSubObject (obj, GL_LINES);
 
 			glDisable (GL_LINE_STIPPLE);
-			break;
+		} break;
 
 		case LDObject::Triangle:
-			compileSubObject (obj, GL_TRIANGLES);
-			break;
+		{	compileSubObject (obj, GL_TRIANGLES);
+		} break;
 
 		case LDObject::Quad:
-			compileSubObject (obj, GL_QUADS);
-			break;
+		{	compileSubObject (obj, GL_QUADS);
+		} break;
 
 		case LDObject::Subfile:
 		{	LDSubfile* ref = static_cast<LDSubfile*> (obj);
@@ -901,14 +900,13 @@
 			if (prev && prev->getType() == LDObject::BFC && static_cast<LDBFC*> (prev)->type == LDBFC::InvertNext)
 				g_glInvert = !g_glInvert;
 
-		for (LDObject * obj : objs)
+			for (LDObject* obj : objs)
 			{	compileList (obj, list);
-				delete obj;
+				obj->deleteSelf();
 			}
 
 			g_glInvert = oldinvert;
-		}
-		break;
+		} break;
 
 		default:
 			break;
@@ -1250,6 +1248,7 @@
 		if (idx == 0xFFFFFF)
 			continue; // White is background; skip
 
+		dlog ("idx: %1", idx);
 		LDObject* obj = LDObject::fromID (idx);
 
 		// If this is an additive single pick and the object is currently selected,
@@ -1557,7 +1556,7 @@
 
 		for (LDObject* obj : objs)
 		{	verts << getVertices (obj);
-			delete obj;
+			obj->deleteSelf();
 		}
 	}
 
@@ -1587,7 +1586,7 @@
 	m_knownVerts << verts;
 	removeDuplicates (m_knownVerts);
 
-	obj->m_glinit = true;
+	obj->setGLInit (true);
 }
 
 // =============================================================================
@@ -1627,13 +1626,13 @@
 // -----------------------------------------------------------------------------
 void GLRenderer::deleteLists (LDObject* obj)
 {	// Delete the lists but only if they have been initialized
-	if (!obj->m_glinit)
+	if (!obj->isGLInit())
 		return;
 
-for (const GL::ListType listType : g_glListTypes)
+	for (const GL::ListType listType : g_glListTypes)
 		glDeleteLists (obj->glLists[listType], 1);
 
-	obj->m_glinit = false;
+	obj->setGLInit (false);
 }
 
 // =============================================================================
@@ -1890,7 +1889,7 @@
 LDOverlay* GLRenderer::findOverlayObject (EFixedCamera cam)
 {	LDOverlay* ovlobj = null;
 
-	for (LDObject * obj : getFile()->getObjects())
+	for (LDObject* obj : getFile()->getObjects())
 	{	if (obj->getType() == LDObject::Overlay && static_cast<LDOverlay*> (obj)->getCamera() == cam)
 		{	ovlobj = static_cast<LDOverlay*> (obj);
 			break;
@@ -1936,14 +1935,11 @@
 			LDObject* nextobj = ovlobj->next();
 
 			if (nextobj && nextobj->getType() == LDObject::Empty)
-			{	getFile()->forgetObject (nextobj);
-				delete nextobj;
-			}
+				nextobj->deleteSelf();
 
 			// If the overlay object was there and the overlay itself is
 			// not, remove the object.
-			getFile()->forgetObject (ovlobj);
-			delete ovlobj;
+			ovlobj->deleteSelf();
 		} elif (meta.img && !ovlobj)
 		{	// Inverse case: image is there but the overlay object is
 			// not, thus create the object.
--- a/src/gui.cc	Wed Dec 18 17:03:35 2013 +0200
+++ b/src/gui.cc	Wed Dec 18 17:44:31 2013 +0200
@@ -266,7 +266,7 @@
 
 	// Delete the objects that were being selected
 	for (LDObject* obj : selCopy)
-		delete obj;
+		obj->deleteSelf();
 
 	refresh();
 	return selCopy.size();
@@ -540,7 +540,7 @@
 LDObject::Type ForgeWindow::getUniformSelectedType()
 {	LDObject::Type result = LDObject::Unidentified;
 
-	for (LDObject * obj : selection())
+	for (LDObject* obj : selection())
 	{	if (result != LDObject::Unidentified && obj->getColor() != result)
 			return LDObject::Unidentified;
 
@@ -606,12 +606,11 @@
 }
 
 // =============================================================================
+// TODO: what the heh?
 // -----------------------------------------------------------------------------
 void ForgeWindow::deleteObjects (QList<LDObject*> objs)
-{	for (LDObject * obj : objs)
-	{	getCurrentDocument()->forgetObject (obj);
-		delete obj;
-	}
+{	for (LDObject* obj : objs)
+		obj->deleteSelf();
 }
 
 // =============================================================================
@@ -785,7 +784,7 @@
 void makeColorComboBox (QComboBox* box)
 {	std::map<int, int> counts;
 
-	for (LDObject * obj : getCurrentDocument()->getObjects())
+	for (LDObject* obj : getCurrentDocument()->getObjects())
 	{	if (!obj->isColored())
 			continue;
 
@@ -908,7 +907,7 @@
 	ui->objectList->clear();
 	LDDocument* f = getCurrentDocument();
 
-for (LDObject * obj : *f)
+for (LDObject* obj : *f)
 		ui->objectList->addItem (obj->qObjListEntry);
 
 #endif
--- a/src/gui_editactions.cc	Wed Dec 18 17:03:35 2013 +0200
+++ b/src/gui_editactions.cc	Wed Dec 18 17:44:31 2013 +0200
@@ -132,8 +132,7 @@
 		// Merge in the inlined objects
 		for (LDObject * inlineobj : objs)
 		{	str line = inlineobj->raw();
-			delete inlineobj;
-
+			inlineobj->deleteSelf();
 			LDObject* newobj = parseLine (line);
 			getCurrentDocument()->insertObj (idx++, newobj);
 			newobj->select();
@@ -141,8 +140,7 @@
 		}
 
 		// Delete the subfile now as it's been inlined.
-		getCurrentDocument()->forgetObject (obj);
-		delete obj;
+		obj->deleteSelf();
 	}
 
 	g_win->refresh();
@@ -183,7 +181,7 @@
 			g_win->R()->compileObject (t);
 
 		// Delete this quad now, it has been split.
-		delete obj;
+		obj->deleteSelf();
 
 		num++;
 	}
--- a/src/history.cc	Wed Dec 18 17:03:35 2013 +0200
+++ b/src/history.cc	Wed Dec 18 17:44:31 2013 +0200
@@ -38,10 +38,14 @@
 
 	const Changeset& set = getChangeset (getPosition());
 	g_fullRefresh = false;
+	dlog ("History: performing undo: set has %1 changes", set.size());
 
 	// Iterate the list in reverse and undo all actions
-	for (auto it = set.end() - 1; it != set.begin(); --it)
-		(*it)->undo();
+	for (int i = set.size() - 1; i >= 0; --i)
+	{	AbstractHistoryEntry* change = set[i];
+		dlog ("Undo change of type %1", change->getType());
+		change->undo();
+	}
 
 	decreasePosition();
 
@@ -56,7 +60,7 @@
 // =============================================================================
 // -----------------------------------------------------------------------------
 void History::redo()
-{	if (getPosition() == (long) m_changesets.size())
+{	if (getPosition() == m_changesets.size())
 		return;
 
 	const Changeset& set = getChangeset (getPosition() + 1);
@@ -84,6 +88,7 @@
 			delete change;
 
 	m_changesets.clear();
+	dlog ("History: cleared");
 }
 
 // =============================================================================
@@ -93,8 +98,15 @@
 		return;
 
 	while (getPosition() < getSize() - 1)
+	{	Changeset last = m_changesets.last();
+
+		for (AbstractHistoryEntry* entry : last)
+			delete entry;
+
 		m_changesets.removeLast();
+	}
 
+	dlog ("History: step added (%1 changes)", m_currentChangeset.size());
 	m_changesets << m_currentChangeset;
 	m_currentChangeset.clear();
 	setPosition (getPosition() + 1);
@@ -111,35 +123,43 @@
 
 	entry->setParent (this);
 	m_currentChangeset << entry;
+	dlog ("History: added entry of type %1", entry->getTypeName());
 }
 
 // =============================================================================
 // -----------------------------------------------------------------------------
 void AddHistory::undo() const
-{	LDDocument* f = getParent()->getFile();
-	LDObject* obj = f->getObject (getIndex());
-	f->forgetObject (obj);
-	delete obj;
-
+{	LDObject* obj = getParent()->getFile()->getObject (getIndex());
+	dlog ("History: undoing addition of #%1", obj->getID());
+	obj->deleteSelf();
 	g_fullRefresh = true;
 }
 
 // =============================================================================
 // -----------------------------------------------------------------------------
 void AddHistory::redo() const
-{	LDDocument* f = getParent()->getFile();
-	LDObject* obj = parseLine (getCode());
-	f->insertObj (getIndex(), obj);
+{	LDObject* obj = parseLine (getCode());
+	getParent()->getFile()->insertObj (getIndex(), obj);
 	g_win->R()->compileObject (obj);
 }
 
 // =============================================================================
+// -----------------------------------------------------------------------------
+DelHistory::DelHistory (int idx, LDObject* obj)
+{	dlog ("obj is: %1, code: %2", obj->getType(), obj->raw());
+	setIndex (idx);
+	setCode (obj->raw());
+}
+
+// =============================================================================
 // heh
 // -----------------------------------------------------------------------------
 void DelHistory::undo() const
-{	LDDocument* f = getParent()->getFile();
+{	dlog ("code: %1", getCode());
+	dlog ("index: %1", getIndex());
 	LDObject* obj = parseLine (getCode());
-	f->insertObj (getIndex(), obj);
+	dlog( "new obj is of type %1 (%2)\n", obj->getType(), obj->getTypeName() );
+	getParent()->getFile()->insertObj (getIndex(), obj);
 	g_win->R()->compileObject (obj);
 }
 
@@ -148,8 +168,7 @@
 void DelHistory::redo() const
 {	LDDocument* f = getParent()->getFile();
 	LDObject* obj = f->getObject (getIndex());
-	f->forgetObject (obj);
-	delete obj;
+	obj->deleteSelf();
 
 	g_fullRefresh = true;
 }
--- a/src/history.h	Wed Dec 18 17:03:35 2013 +0200
+++ b/src/history.h	Wed Dec 18 17:44:31 2013 +0200
@@ -26,15 +26,16 @@
 	virtual ~N##History(){} \
 	virtual void undo() const override; \
 	virtual void redo() const override; \
-	virtual History::Type getType() const override { return History::N; }
+	virtual History::Type getType() const override { return History::N; } \
+	virtual const char* getTypeName() const { return #N; }
 
 class AbstractHistoryEntry;
 
 // =============================================================================
 class History
-{	PROPERTY (private,	long,		Position,	NUM_OPS,		STOCK_WRITE)
+{	PROPERTY (private,	int,				Position,	NUM_OPS,		STOCK_WRITE)
 	PROPERTY (public,		LDDocument*,	File,			NO_OPS,		STOCK_WRITE)
-	PROPERTY (public,		bool,		Ignoring,	BOOL_OPS,	STOCK_WRITE)
+	PROPERTY (public,		bool,				Ignoring,	BOOL_OPS,	STOCK_WRITE)
 
 	public:
 		typedef QList<AbstractHistoryEntry*> Changeset;
@@ -83,9 +84,14 @@
 		virtual ~AbstractHistoryEntry() {}
 		virtual void undo() const {}
 		virtual void redo() const {}
+
 		virtual History::Type getType() const
 		{	return (History::Type) 0;
 		}
+
+		virtual const char* getTypeName() const
+		{	return "";
+		}
 };
 
 // =============================================================================
@@ -97,10 +103,7 @@
 
 	public:
 		IMPLEMENT_HISTORY_TYPE (Del)
-
-		DelHistory (int idx, LDObject* obj) :
-				m_Index (idx),
-				m_Code (obj->raw()) {}
+		DelHistory (int idx, LDObject* obj);
 };
 
 // =============================================================================
--- a/src/ldtypes.cc	Wed Dec 18 17:03:35 2013 +0200
+++ b/src/ldtypes.cc	Wed Dec 18 17:44:31 2013 +0200
@@ -40,20 +40,23 @@
 	m_Selected (false),
 	m_Parent (null),
 	m_File (null),
-	qObjListEntry (null),
-	m_glinit (false)
-{
-	memset (m_coords, 0, sizeof m_coords);
+	m_GLInit (false),
+	qObjListEntry (null)
+{	memset (m_coords, 0, sizeof m_coords);
+	chooseID();
+	g_LDObjects << this;
+}
 
-	// Determine ID
-	int32 id = 1; // 0 is invalid
+// =============================================================================
+// -----------------------------------------------------------------------------
+void LDObject::chooseID()
+{	int32 id = 1; // 0 is invalid
 
 	for (LDObject* obj : g_LDObjects)
 		if (obj->getID() >= id)
 			id = obj->getID() + 1;
 
 	setID (id);
-	g_LDObjects << this;
 }
 
 // =============================================================================
@@ -97,13 +100,13 @@
 
 // =============================================================================
 // -----------------------------------------------------------------------------
-str LDComment::raw()
+str LDComment::raw() const
 {	return fmt ("0 %1", text);
 }
 
 // =============================================================================
 // -----------------------------------------------------------------------------
-str LDSubfile::raw()
+str LDSubfile::raw() const
 {	str val = fmt ("1 %1 %2 ", getColor(), getPosition());
 	val += getTransform().stringRep();
 	val += ' ';
@@ -113,7 +116,7 @@
 
 // =============================================================================
 // -----------------------------------------------------------------------------
-str LDLine::raw()
+str LDLine::raw() const
 {	str val = fmt ("2 %1", getColor());
 
 	for (int i = 0; i < 2; ++i)
@@ -124,7 +127,7 @@
 
 // =============================================================================
 // -----------------------------------------------------------------------------
-str LDTriangle::raw()
+str LDTriangle::raw() const
 {	str val = fmt ("3 %1", getColor());
 
 	for (int i = 0; i < 3; ++i)
@@ -135,7 +138,7 @@
 
 // =============================================================================
 // -----------------------------------------------------------------------------
-str LDQuad::raw()
+str LDQuad::raw() const
 {	str val = fmt ("4 %1", getColor());
 
 	for (int i = 0; i < 4; ++i)
@@ -146,7 +149,7 @@
 
 // =============================================================================
 // -----------------------------------------------------------------------------
-str LDCondLine::raw()
+str LDCondLine::raw() const
 {	str val = fmt ("5 %1", getColor());
 
 	// Add the coordinates
@@ -158,19 +161,19 @@
 
 // =============================================================================
 // -----------------------------------------------------------------------------
-str LDError::raw()
+str LDError::raw() const
 {	return contents;
 }
 
 // =============================================================================
 // -----------------------------------------------------------------------------
-str LDVertex::raw()
+str LDVertex::raw() const
 {	return fmt ("0 !LDFORGE VERTEX %1 %2", getColor(), pos);
 }
 
 // =============================================================================
 // -----------------------------------------------------------------------------
-str LDEmpty::raw()
+str LDEmpty::raw() const
 {	return "";
 }
 
@@ -189,7 +192,7 @@
 	"NOCLIP",
 };
 
-str LDBFC::raw()
+str LDBFC::raw() const
 {	return fmt ("0 BFC %1", LDBFC::statements[type]);
 }
 
@@ -263,8 +266,14 @@
 
 // =============================================================================
 // -----------------------------------------------------------------------------
-LDObject::~LDObject()
-{	// If this object was selected, unselect it now
+LDObject::~LDObject() {}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+void LDObject::deleteSelf()
+{	dlog( "#%1: type: %2\n", getID(), getType());
+
+	// If this object was selected, unselect it now
 	if (isSelected())
 		unselect();
 
@@ -277,6 +286,8 @@
 
 	// Remove this object from the list of LDObjects
 	g_LDObjects.removeOne (this);
+
+	delete this;
 }
 
 // =============================================================================
@@ -321,8 +332,8 @@
 {	QList<LDObject*> objs = getFileInfo()->inlineContents (flags);
 
 	// Transform the objects
-for (LDObject * obj : objs)
-	{	// Set the parent now so we know what inlined this.
+	for (LDObject* obj : objs)
+	{	// Set the parent now so we know what inlined the object.
 		obj->setParent (this);
 		transformObject (obj, getTransform(), getPosition(), getColor());
 	}
@@ -333,10 +344,7 @@
 // =============================================================================
 // -----------------------------------------------------------------------------
 long LDObject::getIndex() const
-{
-#ifndef RELEASE
-	assert (getFile() != null);
-#endif
+{	assert (getFile() != null);
 
 	for (int i = 0; i < getFile()->getObjectCount(); ++i)
 		if (getFile()->getObject (i) == this)
@@ -556,8 +564,7 @@
 
 		if (bfc && bfc->type == LDBFC::InvertNext)
 		{	// This is prefixed with an invertnext, thus remove it.
-			getFile()->forgetObject (bfc);
-			delete bfc;
+			bfc->deleteSelf();
 			return;
 		}
 	}
@@ -613,7 +620,7 @@
 
 // =============================================================================
 // -----------------------------------------------------------------------------
-str LDOverlay::raw()
+str LDOverlay::raw() const
 {	return fmt ("0 !LDFORGE OVERLAY %1 %2 %3 %4 %5 %6",
 		getFileName(), getCamera(), getX(), getY(), getWidth(), getHeight());
 }
@@ -636,7 +643,8 @@
 		*ptr = val;
 		str after = obj->raw();
 
-		obj->getFile()->addToHistory (new EditHistory (idx, before, after));
+		if (before != after)
+			obj->getFile()->addToHistory (new EditHistory (idx, before, after));
 	}
 	else
 		*ptr = val;
@@ -713,6 +721,7 @@
 		return;
 	}
 
+	dlog ("Selected #%1\n", getID());
 	getFile()->addToSelection (this);
 }
 
@@ -743,4 +752,44 @@
 
 	assert (false);
 	return "";
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+LDObject* LDObject::createCopy() const
+{	/*
+	LDObject* copy = clone();
+	copy->setFile (null);
+	copy->setGLInit (false);
+	copy->chooseID();
+	copy->setSelected (false);
+	*/
+
+	/*
+	LDObject* copy = getDefault (getType());
+	copy->setColor (getColor());
+
+	if (hasMatrix())
+	{	LDMatrixObject* copyMo = static_cast<LDMatrixObject*> (copy);
+		const LDMatrixObject* mo = static_cast<const LDMatrixObject*> (this);
+		copyMo->setPosition (mo->getPosition());
+		copyMo->setTransform (mo->getTransform());
+	}
+	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->getFileInfo());
+		}
+	}
+	*/
+
+	LDObject* copy = parseLine (raw());
+	return copy;
 }
\ No newline at end of file
--- a/src/ldtypes.h	Wed Dec 18 17:03:35 2013 +0200
+++ b/src/ldtypes.h	Wed Dec 18 17:44:31 2013 +0200
@@ -23,16 +23,17 @@
 #include "types.h"
 
 #define LDOBJ(T) \
+protected: \
+	virtual ~LD##T() {} \
+	virtual LD##T* clone() override { \
+		return new LD##T (*this); \
+	} \
 public: \
-	virtual ~LD##T() {} \
 	virtual LDObject::Type getType() const override { \
 		return LDObject::T; \
 	} \
-	virtual str raw(); \
-	virtual LD##T* clone() { \
-		return new LD##T (*this); \
-	} \
-	virtual void invert();
+	virtual str raw() const override; \
+	virtual void invert() override;
 
 #define LDOBJ_NAME(N)          virtual str getTypeName() const override { return #N; }
 #define LDOBJ_VERTICES(V)      virtual int vertices() const override { return V; }
@@ -62,12 +63,13 @@
 // sub-classes based on this enumerator.
 // =============================================================================
 class LDObject
-{	PROPERTY (public,		bool,			Hidden,		BOOL_OPS,	STOCK_WRITE)
-	PROPERTY (public,		bool,			Selected,	BOOL_OPS,	STOCK_WRITE)
-	PROPERTY (public,		LDObject*,	Parent,		NO_OPS,		STOCK_WRITE)
-	PROPERTY (public,		LDDocument*,		File,			NO_OPS,		STOCK_WRITE)
-	PROPERTY	(private,	int32,		ID,			NUM_OPS,		STOCK_WRITE)
-	PROPERTY (public,		int,			Color,		NUM_OPS,		CUSTOM_WRITE)
+{	PROPERTY (public,		bool,				Hidden,		BOOL_OPS,	STOCK_WRITE)
+	PROPERTY (public,		bool,				Selected,	BOOL_OPS,	STOCK_WRITE)
+	PROPERTY (public,		LDObject*,		Parent,		NO_OPS,		STOCK_WRITE)
+	PROPERTY (public,		LDDocument*,	File,			NO_OPS,		STOCK_WRITE) // TODO: rename~
+	PROPERTY	(private,	int32,			ID,			NUM_OPS,		STOCK_WRITE)
+	PROPERTY (public,		int,				Color,		NUM_OPS,		CUSTOM_WRITE)
+	PROPERTY (public,		bool,				GLInit,		BOOL_OPS,	STOCK_WRITE)
 
 	public:
 		// Object type codes. Codes are sorted in order of significance.
@@ -76,7 +78,7 @@
 			Quad,           // Object represents a quadrilateral
 			Triangle,       // Object represents a triangle
 			Line,           // Object represents a line
-			CondLine,        // Object represents a conditional line
+			CondLine,       // Object represents a conditional line
 			Vertex,         // Object is a vertex, LDForge extension object
 			BFC,            // Object represents a BFC statement
 			Overlay,        // Object contains meta-info about an overlay image.
@@ -88,36 +90,85 @@
 		};
 
 		LDObject();
-		virtual ~LDObject();
+
+		// Makes a copy of this object
+		LDObject*					createCopy() const;
+
+		// Deletes this object
+		void							deleteSelf();
+
+		// Index (i.e. line number) of this object
+		long							getIndex() const;
+
+		// Type enumerator of this object
+		virtual LDObject::Type	getType() const;
+
+		// Get a vertex by index
+		const vertex&				getVertex (int i) const;
+
+		// Type name of this object
+		virtual str					getTypeName() const;
+
+		// Does this object have a matrix and position? (see LDMatrixObject)
+		virtual bool				hasMatrix() const;
+
+		// Inverts this object (winding is reversed)
+		virtual void				invert();
+
+		// Is this object colored?
+		virtual bool				isColored() const;
+
+		// Does this object have meaning in the part model?
+		virtual bool				isScemantic() const;
+
+		// Moves this object using the given vertex as a movement List
+		void							move (vertex vect);
+
+		// Object after this in the current file
+		LDObject*					next() const;
+
+		// Object prior to this in the current file
+		LDObject*					prev() const;
 
-		virtual LDObject* clone()
-		{	return 0;   // Creates a new LDObject identical to this one.
-		}
-		long getIndex() const;                      // Index (i.e. line number) of this object
-		virtual LDObject::Type getType() const;     // Type enumerator of this object
-		const vertex& getVertex (int i) const;      // Get a vertex by index
-		virtual str getTypeName() const;            // Type name of this object
-		virtual bool hasMatrix() const;             // Does this object have a matrix and position? (see LDMatrixObject)
-		virtual void invert();                      // Inverts this object (winding is reversed)
-		virtual bool isColored() const;             // Is this object colored?
-		virtual bool isScemantic() const;           // Does this object have meaning in the part model?
-		void move (vertex vect);                    // Moves this object using the given vertex as a movement List
-		LDObject* next() const;                     // Object after this in the current file
-		LDObject* prev() const;                     // Object prior to this in the current file
-		virtual str raw() {	return ""; }            // This object as LDraw code
-		void replace (LDObject* other);             // Replace this LDObject with another LDObject. Object is deleted in the process.
-		void select();
-		void setVertex (int i, const vertex& vert); // Set a vertex to the given value
-		void setVertexCoord (int i, Axis ax, double value); // Set a single coordinate of a vertex
-		void swap (LDObject* other);                // Swap this object with another.
-		LDObject* topLevelParent();                 // What object in the current file ultimately references this?
-		void unselect();
-		virtual int vertices() const;             // Number of vertices this object has
+		// This object as LDraw code
+		virtual						str raw() const = 0;
+
+		// Replace this LDObject with another LDObject. Object is deleted in the process.
+		void							replace (LDObject* other);
+
+		// Selects this object.
+		void							select();
+
+		// Set a vertex to the given value
+		void							setVertex (int i, const vertex& vert);
+
+		// Set a single coordinate of a vertex
+		void							setVertexCoord (int i, Axis ax, double value);
+
+		// Swap this object with another.
+		void							swap (LDObject* other);
 
-		static str typeName (LDObject::Type type); // Get type name by enumerator
-		static LDObject* getDefault (const LDObject::Type type); // Returns a sample object by the given enumerator
-		static void moveObjects (QList<LDObject*> objs, const bool up); // TODO: move this to LDDocument?
-		static str describeObjects (const QList<LDObject*>& objs); // Get a description of a list of LDObjects
+		// What object in the current file ultimately references this?
+		LDObject*					topLevelParent();
+
+		// Removes this object from selection // TODO: rename to deselect?
+		void							unselect();
+
+		// Number of vertices this object has // TODO: rename to getNumVertices
+		virtual int					vertices() const;
+
+		// Get type name by enumerator
+		static str typeName (LDObject::Type type);
+
+		// Returns a sample object by the given enumerator
+		// TODO: Use of this function only really results in hacks, get rid of it!
+		static LDObject* getDefault (const LDObject::Type type);
+
+		// TODO: move this to LDDocument?
+		static void moveObjects (QList<LDObject*> objs, const bool up);
+
+		// Get a description of a list of LDObjects
+		static str describeObjects (const QList<LDObject*>& objs);
 		static LDObject* fromID (int id);
 
 		// TODO: make these private!
@@ -128,10 +179,17 @@
 		QListWidgetItem* qObjListEntry;
 
 	protected:
-		bool m_glinit;
-		friend class GLRenderer;
+		// LDObjects are to be deleted with the deleteSelf() method, not with
+		// operator delete. This is because it seems virtual functions cannot
+		// be properly called from the destructor, thus a normal method must
+		// be used instead. The destructor also doesn't seem to be able to
+		// be private without causing a truckload of problems so it's protected
+		// instead.
+		virtual ~LDObject();
+		void chooseID();
 
 	private:
+		virtual LDObject* clone() = 0;
 		LDSharedVertex*	m_coords[4];
 };
 
@@ -338,7 +396,7 @@
 		}
 
 		// Inlines this subfile. Note that return type is an array of heap-allocated
-		// LDObject-clones, they must be deleted one way or another.
+		// LDObject copies, they must be deleted manually.
 		QList<LDObject*> inlineContents (InlineFlags flags);
 };
 
--- a/src/main.h	Wed Dec 18 17:03:35 2013 +0200
+++ b/src/main.h	Wed Dec 18 17:44:31 2013 +0200
@@ -100,6 +100,16 @@
 #define FUNCNAME __func__
 #endif // __GNUC__
 
+#ifdef IN_IDE_PARSER
+void dlog(void, ...) {}
+#else
+# ifdef DEBUG
+#  define dlog(...) log( str( __PRETTY_FUNCTION__ ) + ": " __VA_ARGS__)
+# else
+#  define dlog(...)
+# endif // DEBUG
+#endif // IN_IDE_PARSER
+
 // Replace assert with a version that shows a GUI dialog if possible.
 // On Windows I just can't get the actual error messages otherwise.
 void assertionFailure (const char* file, int line, const char* funcname, const char* expr);
--- a/src/types.cc	Wed Dec 18 17:03:35 2013 +0200
+++ b/src/types.cc	Wed Dec 18 17:44:31 2013 +0200
@@ -535,7 +535,7 @@
 
 			for (LDObject * obj : objs)
 			{	calcObject (obj);
-				delete obj;
+				obj->deleteSelf();
 			}
 		}
 		break;

mercurial