Refactor edit history

Sun, 06 Sep 2015 03:00:28 +0300

author
Teemu Piippo <crimsondusk64@gmail.com>
date
Sun, 06 Sep 2015 03:00:28 +0300
changeset 983
05ba93066194
parent 982
a3a2e62a581b
child 984
a7b6f987d269

Refactor edit history

src/editHistory.cpp file | annotate | diff | comparison | revisions
src/editHistory.h file | annotate | diff | comparison | revisions
src/ldDocument.cpp file | annotate | diff | comparison | revisions
src/ldDocument.h file | annotate | diff | comparison | revisions
src/ldObject.cpp file | annotate | diff | comparison | revisions
src/mainwindow.cpp file | annotate | diff | comparison | revisions
src/mainwindow.h file | annotate | diff | comparison | revisions
--- a/src/editHistory.cpp	Sun Sep 06 01:52:37 2015 +0300
+++ b/src/editHistory.cpp	Sun Sep 06 03:00:28 2015 +0300
@@ -23,23 +23,19 @@
 #include "mainwindow.h"
 #include "glRenderer.h"
 
-// =============================================================================
-//
-History::History() :
-	m_position (-1),
-	m_isIgnoring (false) {}
+EditHistory::EditHistory (LDDocument* document) :
+	m_document (document),
+	m_isIgnoring (false),
+	m_position (-1) {}
 
-// =============================================================================
-//
-void History::undo()
+void EditHistory::undo()
 {
 	if (m_changesets.isEmpty() or position() == -1)
 		return;
 
 	// Don't take the changes done here as actual edits to the document
 	setIgnoring (true);
-
-	const Changeset& set = getChangeset (position());
+	const Changeset& set = changesetAt (position());
 
 	// Iterate the list in reverse and undo all actions
 	for (int i = set.size() - 1; i >= 0; --i)
@@ -49,53 +45,42 @@
 	}
 
 	m_position--;
-	g_win->refresh();
-	g_win->updateActions();
-	dprint ("Position is now %1", position());
 	setIgnoring (false);
+	emit undone();
 }
 
-// =============================================================================
-//
-void History::redo()
+void EditHistory::redo()
 {
 	if (position() == m_changesets.size())
 		return;
 
 	setIgnoring (true);
-	const Changeset& set = getChangeset (position() + 1);
+	const Changeset& set = changesetAt (position() + 1);
 
-	// Redo things - in the order as they were done in the first place
+	// Redo things in original order
 	for (const AbstractHistoryEntry* change : set)
 		change->redo();
 
-	setPosition (position() + 1);
-	g_win->refresh();
-	g_win->updateActions();
-	dprint ("Position is now %1", position());
+	++m_position;
 	setIgnoring (false);
+	emit redone();
 }
 
-// =============================================================================
-//
-void History::clear()
+void EditHistory::clear()
 {
 	for (Changeset set : m_changesets)
-		for (AbstractHistoryEntry* change : set)
-			delete change;
+	for (AbstractHistoryEntry* change : set)
+		delete change;
 
 	m_changesets.clear();
-	dprint ("History: cleared");
 }
 
-// =============================================================================
-//
-void History::addStep()
+void EditHistory::addStep()
 {
 	if (m_currentChangeset.isEmpty())
 		return;
 
-	while (position() < getSize() - 1)
+	while (position() < size() - 1)
 	{
 		Changeset last = m_changesets.last();
 
@@ -105,16 +90,13 @@
 		m_changesets.removeLast();
 	}
 
-//	dprint ("History: step added (%1 changes)", m_currentChangeset.size());
 	m_changesets << m_currentChangeset;
 	m_currentChangeset.clear();
-	setPosition (position() + 1);
-	g_win->updateActions();
+	++m_position;
+	emit stepAdded();
 }
 
-// =============================================================================
-//
-void History::add (AbstractHistoryEntry* entry)
+void EditHistory::add (AbstractHistoryEntry* entry)
 {
 	if (isIgnoring())
 	{
@@ -124,80 +106,128 @@
 
 	entry->setParent (this);
 	m_currentChangeset << entry;
-//	dprint ("History: added entry of type %1", entry->getTypeName());
+}
+
+int EditHistory::size() const
+{
+	return m_changesets.size();
+}
+
+const EditHistory::Changeset& EditHistory::changesetAt (int pos) const
+{
+	return m_changesets[pos];
 }
 
-// =============================================================================
-//
-void AddHistory::undo() const
+int EditHistory::position()
+{
+	return m_position;
+}
+
+bool EditHistory::isIgnoring() const
 {
-	LDObject* obj = parent()->document()->getObject (index());
-	obj->destroy();
+	return m_isIgnoring;
+}
+
+void EditHistory::setIgnoring (bool value)
+{
+	m_isIgnoring = value;
 }
 
-// =============================================================================
-//
-void AddHistory::redo() const
+LDDocument* EditHistory::document() const
 {
-	LDObject* obj = ParseLine (code());
-	parent()->document()->insertObj (index(), obj);
-	g_win->renderer()->compileObject (obj);
+	return m_document;
 }
 
-// =============================================================================
+//
+// ---------------------------------------------------------------------------------------------------------------------
 //
-DelHistory::DelHistory (int idx, LDObject* obj) :
+
+AbstractHistoryEntry::AbstractHistoryEntry() {}
+AbstractHistoryEntry::~AbstractHistoryEntry() {}
+
+EditHistory* AbstractHistoryEntry::parent() const
+{
+	return m_parent;
+}
+
+void AbstractHistoryEntry::setParent (EditHistory* parent)
+{
+	m_parent = parent;
+}
+
+//
+// ---------------------------------------------------------------------------------------------------------------------
+//
+
+AddHistoryEntry::AddHistoryEntry (int idx, LDObject* obj) :
 	m_index (idx),
 	m_code (obj->asText()) {}
 
-// =============================================================================
-// heh
-//
-void DelHistory::undo() const
+void AddHistoryEntry::undo() const
 {
-	LDObject* obj = ParseLine (code());
-	parent()->document()->insertObj (index(), obj);
-	g_win->renderer()->compileObject (obj);
+	parent()->document()->getObject (m_index)->destroy();
+}
+
+void AddHistoryEntry::redo() const
+{
+	parent()->document()->insertObj (m_index, ParseLine (m_code));
 }
 
-// =============================================================================
+//
+// ---------------------------------------------------------------------------------------------------------------------
 //
-void DelHistory::redo() const
+
+DelHistoryEntry::DelHistoryEntry (int idx, LDObject* obj) :
+	AddHistoryEntry (idx, obj) {}
+
+void DelHistoryEntry::undo() const
 {
-	LDObject* obj = parent()->document()->getObject (index());
-	obj->destroy();
+	AddHistoryEntry::redo();
+}
+
+void DelHistoryEntry::redo() const
+{
+	AddHistoryEntry::undo();
 }
 
-// =============================================================================
+//
+// ---------------------------------------------------------------------------------------------------------------------
 //
-void EditHistory::undo() const
+
+EditHistoryEntry::EditHistoryEntry (int idx, QString oldCode, QString newCode) :
+	m_index (idx),
+	m_oldCode (oldCode),
+	m_newCode (newCode) {}
+
+void EditHistoryEntry::undo() const
 {
-	LDObject* obj = g_win->currentDocument()->getObject (index());
-	LDObject* newobj = ParseLine (oldCode());
+	LDObject* obj = parent()->document()->getObject (m_index);
+	LDObject* newobj = ParseLine (m_oldCode);
 	obj->replace (newobj);
-	g_win->renderer()->compileObject (newobj);
 }
 
-// =============================================================================
-//
-void EditHistory::redo() const
+void EditHistoryEntry::redo() const
 {
-	LDObject* obj = g_win->currentDocument()->getObject (index());
-	LDObject* newobj = ParseLine (newCode());
+	LDObject* obj = parent()->document()->getObject (m_index);
+	LDObject* newobj = ParseLine (m_newCode);
 	obj->replace (newobj);
-	g_win->renderer()->compileObject (newobj);
 }
 
-// =============================================================================
+//
+// ---------------------------------------------------------------------------------------------------------------------
 //
-void SwapHistory::undo() const
+
+SwapHistoryEntry::SwapHistoryEntry (int a, int b) :
+	m_a (a),
+	m_b (b) {}
+
+
+void SwapHistoryEntry::undo() const
 {
-	LDObject::fromID (a)->swap (LDObject::fromID (b));
+	LDObject::fromID (m_a)->swap (LDObject::fromID (m_b));
 }
 
-// =============================================================================
-//
-void SwapHistory::redo() const
+void SwapHistoryEntry::redo() const
 {
 	undo();
 }
--- a/src/editHistory.h	Sun Sep 06 01:52:37 2015 +0300
+++ b/src/editHistory.h	Sun Sep 06 03:00:28 2015 +0300
@@ -20,155 +20,98 @@
 #include "main.h"
 #include "ldObject.h"
 
-#define IMPLEMENT_HISTORY_TYPE(N)					\
-	~N##History() {}								\
-	void undo() const override;						\
-	void redo() const override;						\
-													\
-	History::EHistoryType getType() const override	\
-	{												\
-		return History::E##N##History;				\
-	}												\
-													\
-	QString getTypeName() const override			\
-	{												\
-		return #N;									\
-	}
-
 class AbstractHistoryEntry;
 
-// =============================================================================
-class History
+class EditHistory : public QObject
 {
-	PROPERTY (private,	int,				position,	setPosition,	STOCK_WRITE)
-	PROPERTY (public,	LDDocument*,	document,	setDocument,	STOCK_WRITE)
-	PROPERTY (public,	bool,				isIgnoring,	setIgnoring,	STOCK_WRITE)
-
-public:
-	typedef QList<AbstractHistoryEntry*> Changeset;
-
-	enum EHistoryType
-	{
-		EDelHistory,
-		EEditHistory,
-		EAddHistory,
-		EMoveHistory,
-		ESwapHistory,
-	};
-
-	History();
-	void undo();
-	void redo();
-	void clear();
-
-	void addStep();
-	void add (AbstractHistoryEntry* entry);
-
-	inline long getSize() const
-	{
-		return m_changesets.size();
-	}
-
-	inline History& operator<< (AbstractHistoryEntry* entry)
-	{
-		add (entry);
-		return *this;
-	}
-
-	inline const Changeset& getChangeset (long pos) const
-	{
-		return m_changesets[pos];
-	}
-
-private:
-	Changeset			m_currentChangeset;
-	QList<Changeset>	m_changesets;
-};
-
-// =============================================================================
-//
-class AbstractHistoryEntry
-{
-	PROPERTY (public,	History*,	parent,	setParent,	STOCK_WRITE)
+	Q_OBJECT
 
 public:
-	virtual ~AbstractHistoryEntry() {}
-	virtual void undo() const = 0;
-	virtual void redo() const = 0;
-	virtual History::EHistoryType getType() const = 0;
-	virtual QString getTypeName() const = 0;
+	using Changeset = QList<AbstractHistoryEntry*>;
+
+	EditHistory (LDDocument* document);
+
+	void add (AbstractHistoryEntry* entry);
+	void addStep();
+	const Changeset& changesetAt (int pos) const;
+	void clear();
+	LDDocument* document() const;
+	bool isIgnoring() const;
+	int position();
+	void redo();
+	void setIgnoring (bool value);
+	int size() const;
+	void undo();
+
+signals:
+	void undone();
+	void redone();
+	void stepAdded();
+
+private:
+	LDDocument* m_document;
+	Changeset m_currentChangeset;
+	QList<Changeset> m_changesets;
+	bool m_isIgnoring;
+	int m_position;
 };
 
-// =============================================================================
-//
-class DelHistory : public AbstractHistoryEntry
+class AbstractHistoryEntry
 {
-	PROPERTY (private,	int,		index,	setIndex,	STOCK_WRITE)
-	PROPERTY (private,	QString,	code,	setCode,	STOCK_WRITE)
-
 public:
-	IMPLEMENT_HISTORY_TYPE (Del)
-	DelHistory (int idx, LDObject* obj);
-};
+	AbstractHistoryEntry();
+	virtual ~AbstractHistoryEntry();
 
-// =============================================================================
-//
-class EditHistory : public AbstractHistoryEntry
-{
-	PROPERTY (private,	int, 		index,		setIndex,	STOCK_WRITE)
-	PROPERTY (private,	QString,	oldCode,	setOldCode,	STOCK_WRITE)
-	PROPERTY (private,	QString,	newCode,	setNewCode,	STOCK_WRITE)
+	EditHistory* parent() const;
+	virtual void redo() const = 0;
+	void setParent (EditHistory* parent);
+	virtual void undo() const = 0;
 
-public:
-	IMPLEMENT_HISTORY_TYPE (Edit)
-
-	EditHistory (int idx, QString oldCode, QString newCode) :
-		m_index (idx),
-		m_oldCode (oldCode),
-		m_newCode (newCode) {}
+private:
+	EditHistory* m_parent;
 };
 
-// =============================================================================
-//
-class AddHistory : public AbstractHistoryEntry
+class AddHistoryEntry : public AbstractHistoryEntry
 {
-	PROPERTY (private,	int,		index,	setIndex,	STOCK_WRITE)
-	PROPERTY (private,	QString,	code,	setCode,	STOCK_WRITE)
-
 public:
-	IMPLEMENT_HISTORY_TYPE (Add)
-
-	AddHistory (int idx, LDObject* obj) :
-		m_index (idx),
-		m_code (obj->asText()) {}
+	AddHistoryEntry (int idx, LDObject* obj);
+	void undo() const override;
+	void redo() const override;
+	
+private:
+	int m_index;
+	QString m_code;
 };
 
-// =============================================================================
-//
-class MoveHistory : public AbstractHistoryEntry
+class DelHistoryEntry : public AddHistoryEntry
 {
 public:
-	IMPLEMENT_HISTORY_TYPE (Move)
-
-	QList<int> indices;
-	Vertex dest;
-
-	MoveHistory (QList<int> indices, Vertex dest) :
-			indices (indices),
-			dest (dest) {}
+	DelHistoryEntry (int idx, LDObject* obj);
+	void undo() const override;
+	void redo() const override;
 };
 
-// =============================================================================
-//
-class SwapHistory : public AbstractHistoryEntry
+class EditHistoryEntry : public AbstractHistoryEntry
 {
 public:
-	IMPLEMENT_HISTORY_TYPE (Swap)
+	EditHistoryEntry (int idx, QString oldCode, QString newCode);
+	void undo() const override;
+	void redo() const override;
+	
+private:
+	int m_index;
+	QString m_oldCode;
+	QString m_newCode;
+};
 
-	SwapHistory (int a, int b) :
-		a (a),
-		b (b) {}
+class SwapHistoryEntry : public AbstractHistoryEntry
+{
+public:
+	SwapHistoryEntry (int a, int b);
+	void undo() const override;
+	void redo() const override;
 
 private:
-	int a, b;
+	int m_a;
+	int m_b;
 };
--- a/src/ldDocument.cpp	Sun Sep 06 01:52:37 2015 +0300
+++ b/src/ldDocument.cpp	Sun Sep 06 03:00:28 2015 +0300
@@ -46,7 +46,7 @@
 LDDocument::LDDocument (QObject* parent) :
 	QObject (parent),
 	HierarchyElement (parent),
-	m_history (new History),
+	m_history (new EditHistory (this)),
 	m_isCache (true),
 	m_verticesOutdated (true),
 	m_needVertexMerge (true),
@@ -55,7 +55,6 @@
 {
 	setSavePosition (-1);
 	setTabIndex (-1);
-	m_history->setDocument (this);
 	m_needsReCache = true;
 }
 
@@ -81,7 +80,7 @@
 	return m_objects;
 }
 
-History* LDDocument::history() const
+EditHistory* LDDocument::history() const
 {
 	return m_history;
 }
@@ -172,7 +171,7 @@
 
 void LDDocument::addToHistory (AbstractHistoryEntry* entry)
 {
-	*history() << entry;
+	history()->add (entry);
 }
 
 void LDDocument::close()
@@ -961,7 +960,7 @@
 //
 int LDDocument::addObject (LDObject* obj)
 {
-	history()->add (new AddHistory (objects().size(), obj));
+	history()->add (new AddHistoryEntry (objects().size(), obj));
 	m_objects << obj;
 	addKnownVertices (obj);
 	obj->setDocument (this);
@@ -984,7 +983,7 @@
 //
 void LDDocument::insertObj (int pos, LDObject* obj)
 {
-	history()->add (new AddHistory (pos, obj));
+	history()->add (new AddHistoryEntry (pos, obj));
 	m_objects.insert (pos, obj);
 	obj->setDocument (this);
 	m_window->renderer()->compileObject (obj);
@@ -1023,7 +1022,7 @@
 
 		if (not isCache() and not m_beingDestroyed)
 		{
-			history()->add (new DelHistory (idx, obj));
+			history()->add (new DelHistoryEntry (idx, obj));
 			m_objectVertices.remove (obj);
 		}
 
@@ -1057,7 +1056,7 @@
 	{
 		QString oldcode = getObject (idx)->asText();
 		QString newcode = obj->asText();
-		*m_history << new EditHistory (idx, oldcode, newcode);
+		m_history->add (new EditHistoryEntry (idx, oldcode, newcode));
 	}
 
 	m_objectVertices.remove (m_objects[idx]);
@@ -1282,7 +1281,7 @@
 	{
 		m_objects[b] = one;
 		m_objects[a] = other;
-		addToHistory (new SwapHistory (one->id(), other->id()));
+		addToHistory (new SwapHistoryEntry (one->id(), other->id()));
 	}
 }
 
--- a/src/ldDocument.h	Sun Sep 06 01:52:37 2015 +0300
+++ b/src/ldDocument.h	Sun Sep 06 03:00:28 2015 +0300
@@ -23,7 +23,7 @@
 #include "editHistory.h"
 #include "glShared.h"
 
-class History;
+class EditHistory;
 class OpenProgressDialog;
 struct LDGLData;
 class GLCompiler;
@@ -65,7 +65,7 @@
 	const LDObjectList& getSelection() const;
 	LDGLData* glData();
 	bool hasUnsavedChanges() const;
-	History* history() const;
+	EditHistory* history() const;
 	void initializeCachedData();
 	LDObjectList inlineContents (bool deep, bool renderinline);
 	QList<LDPolygon> inlinePolygons();
@@ -104,7 +104,7 @@
 	QString m_fullPath;
 	QString m_defaultName;
 	LDObjectList m_objects;
-	History* m_history;
+	EditHistory* m_history;
 	bool m_isCache;
 	bool m_verticesOutdated;
 	bool m_needVertexMerge;
--- a/src/ldObject.cpp	Sun Sep 06 01:52:37 2015 +0300
+++ b/src/ldObject.cpp	Sun Sep 06 03:00:28 2015 +0300
@@ -785,7 +785,7 @@
 
 		if (before != after)
 		{
-			obj->document()->addToHistory (new EditHistory (idx, before, after));
+			obj->document()->addToHistory (new EditHistoryEntry (idx, before, after));
 			g_win->renderer()->compileObject (obj);
 			g_win->currentDocument()->redoVertices();
 		}
--- a/src/mainwindow.cpp	Sun Sep 06 01:52:37 2015 +0300
+++ b/src/mainwindow.cpp	Sun Sep 06 03:00:28 2015 +0300
@@ -1033,10 +1033,10 @@
 {
 	if (m_currentDocument != null and m_currentDocument->history() != null)
 	{
-		History* his = m_currentDocument->history();
+		EditHistory* his = m_currentDocument->history();
 		int pos = his->position();
 		ui.actionUndo->setEnabled (pos != -1);
-		ui.actionRedo->setEnabled (pos < (long) his->getSize() - 1);
+		ui.actionRedo->setEnabled (pos < (long) his->size() - 1);
 	}
 
 	ui.actionWireframe->setChecked (m_configOptions.drawWireframe());
@@ -1085,6 +1085,14 @@
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
+void MainWindow::historyTraversed()
+{
+	updateActions();
+	refresh();
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
 void MainWindow::loadShortcuts()
 {
 	for (QAction* act : findChildren<QAction*>())
@@ -1216,12 +1224,17 @@
 //
 LDDocument* MainWindow::newDocument (bool cache)
 {
-	m_documents.append (new LDDocument (this));
+	LDDocument* document = new LDDocument (this);
+	m_documents.append (document);
+
+	connect (document->history(), SIGNAL (undone()), this, SLOT (historyTraversed()));
+	connect (document->history(), SIGNAL (redone()), this, SLOT (historyTraversed()));
+	connect (document->history(), SIGNAL (stepAdded()), this, SLOT (updateActions()));
 
 	if (not cache)
-		m_documents.last()->openForEditing();
+		document->openForEditing();
 
-	return m_documents.last();
+	return document;
 }
 
 // ---------------------------------------------------------------------------------------------------------------------
--- a/src/mainwindow.h	Sun Sep 06 01:52:37 2015 +0300
+++ b/src/mainwindow.h	Sun Sep 06 03:00:28 2015 +0300
@@ -105,7 +105,7 @@
 	void spawnContextMenu (const QPoint pos);
 	int suggestInsertPoint();
 	void syncSettings();
-	void updateActions();
+	Q_SLOT void updateActions();
 	void updateColorToolbar();
 	void updateDocumentList();
 	void updateDocumentListItem (LDDocument* doc);
@@ -119,6 +119,7 @@
 	void actionTriggered();
 	void circleToolSegmentsChanged();
 	void closeTab (int tabindex);
+	void historyTraversed();
 	void ringToolHiResClicked (bool clicked);
 	void tabSelected();
 	void updatePrimitives();

mercurial