Split LDFileLoader (now LDDocumentLoader) into its own files

Sun, 06 Sep 2015 01:22:25 +0300

author
Teemu Piippo <crimsondusk64@gmail.com>
date
Sun, 06 Sep 2015 01:22:25 +0300
changeset 980
4a95c6b06ebe
parent 979
880d3fe9ac7c
child 981
5d5d84ab2c48

Split LDFileLoader (now LDDocumentLoader) into its own files

CMakeLists.txt file | annotate | diff | comparison | revisions
src/documentloader.cpp file | annotate | diff | comparison | revisions
src/documentloader.h file | annotate | diff | comparison | revisions
src/ldDocument.cpp file | annotate | diff | comparison | revisions
src/ldDocument.h file | annotate | diff | comparison | revisions
--- a/CMakeLists.txt	Sat Sep 05 23:55:06 2015 +0300
+++ b/CMakeLists.txt	Sun Sep 06 01:22:25 2015 +0300
@@ -38,6 +38,7 @@
 	src/crashCatcher.cpp
 	src/dialogs.cpp
 	src/documentation.cpp
+	src/documentloader.cpp
 	src/editHistory.cpp
 	src/glRenderer.cpp
 	src/glCompiler.cpp
@@ -103,6 +104,7 @@
 	src/ldpaths.h
 	src/hierarchyelement.h
 	src/guiutilities.h
+	src/documentloader.h
 	src/dialogs/colorselector.h
 	src/dialogs/configdialog.h
 	src/dialogs/ldrawpathdialog.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/documentloader.cpp	Sun Sep 06 01:22:25 2015 +0300
@@ -0,0 +1,160 @@
+/*
+ *  LDForge: LDraw parts authoring CAD
+ *  Copyright (C) 2013 - 2015 Teemu 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 <QFile>
+#include "documentloader.h"
+#include "ldDocument.h"
+#include "ldObject.h"
+#include "mainwindow.h"
+#include "dialogs/openprogressdialog.h"
+
+DocumentLoader::DocumentLoader (bool onForeground, QObject *parent) :
+	QObject (parent),
+	m_warningCount (0),
+	m_isDone (false),
+	m_hasAborted (false),
+	m_isOnForeground (onForeground) {}
+
+bool DocumentLoader::hasAborted()
+{
+	return m_hasAborted;
+}
+
+bool DocumentLoader::isDone() const
+{
+	return m_isDone;
+}
+
+int DocumentLoader::progress() const
+{
+	return m_progress;
+}
+
+int DocumentLoader::warningCount() const
+{
+	return m_warningCount;
+}
+
+bool DocumentLoader::isOnForeground() const
+{
+	return m_isOnForeground;
+}
+
+const LDObjectList& DocumentLoader::objects() const
+{
+	return m_objects;
+}
+
+void DocumentLoader::read (QIODevice* fp)
+{
+	if (fp and fp->isOpen())
+	{
+		while (not fp->atEnd())
+			m_lines << QString::fromUtf8 (fp->readLine());
+	}
+}
+
+void DocumentLoader::start()
+{
+	m_isDone = false;
+	m_progress = 0;
+	m_hasAborted = false;
+
+	if (isOnForeground())
+	{
+		// Show a progress dialog if we're loading the main ldDocument.here so we can show progress updates and keep the
+		// WM posted that we're still here.
+		m_progressDialog = new OpenProgressDialog (g_win);
+		m_progressDialog->setNumLines (m_lines.size());
+		m_progressDialog->setModal (true);
+		m_progressDialog->show();
+		connect (this, SIGNAL (workDone()), m_progressDialog, SLOT (accept()));
+		connect (m_progressDialog, SIGNAL (rejected()), this, SLOT (abort()));
+	}
+	else
+		m_progressDialog = null;
+
+	// Begin working
+	work (0);
+}
+
+void DocumentLoader::work (int i)
+{
+	// User wishes to abort, so stop here now.
+	if (hasAborted())
+	{
+		for (LDObject* obj : m_objects)
+			obj->destroy();
+
+		m_objects.clear();
+		m_isDone = true;
+		return;
+	}
+
+	// Parse up to 200 lines per iteration
+	int max = i + 200;
+
+	for (; i < max and i < (int) m_lines.size(); ++i)
+	{
+		QString line = m_lines[i];
+
+		// Trim the trailing newline
+		while (line.endsWith ("\n") or line.endsWith ("\r"))
+			line.chop (1);
+
+		LDObject* obj = ParseLine (line);
+
+		// Check for parse errors and warn about them
+		if (obj->type() == OBJ_Error)
+		{
+			print ("Couldn't parse line #%1: %2", progress() + 1, static_cast<LDError*> (obj)->reason());
+			++m_warningCount;
+		}
+
+		m_objects << obj;
+	}
+
+	m_progress = i;
+
+	if (m_progressDialog)
+		m_progressDialog->setProgress (i);
+
+	if (i >= m_lines.size() - 1)
+	{
+		emit workDone();
+		m_isDone = true;
+	}
+	else
+	{
+		// If we have a dialog to show progress output to, we cannot just call work() again immediately as the dialog
+		// needs to be updated as well. Thus, we take a detour through the event loop by using the meta-object system.
+		//
+		// This terminates the loop here and control goes back to the function which called the file loader. It will
+		// keep processing the event loop until we're ready (see loadFileContents), thus the event loop will eventually
+		// catch the invokation we throw here and send us back.
+		if (isOnForeground())
+			QMetaObject::invokeMethod (this, "work", Qt::QueuedConnection, Q_ARG (int, i));
+		else
+			work (i);
+	}
+}
+
+void DocumentLoader::abort()
+{
+	m_hasAborted = true;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/documentloader.h	Sun Sep 06 01:22:25 2015 +0300
@@ -0,0 +1,61 @@
+/*
+ *  LDForge: LDraw parts authoring CAD
+ *  Copyright (C) 2013 - 2015 Teemu 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"
+
+//
+// DocumentLoader
+//
+// Loads the given file and parses it to LDObjects. It's a separate class so as to be able to do the work progressively
+// through the event loop, allowing the program to maintain responsivity during loading.
+//
+class DocumentLoader : public QObject
+{
+	Q_OBJECT
+
+public:
+	DocumentLoader (bool onForeground = false, QObject* parent = 0);
+
+	Q_SLOT void abort();
+	bool hasAborted();
+	bool isDone() const;
+	bool isOnForeground() const;
+	const LDObjectList& objects() const;
+	int progress() const;
+	void read (QIODevice* fp);
+	Q_SLOT void start();
+	int warningCount() const;
+
+private:
+	class OpenProgressDialog* m_progressDialog;
+	LDObjectList m_objects;
+	QStringList m_lines;
+	int m_progress;
+	int m_warningCount;
+	bool m_isDone;
+	bool m_hasAborted;
+	bool m_isOnForeground;
+
+private slots:
+	void work (int i);
+
+signals:
+	void progressUpdate (int progress);
+	void workDone();
+};
--- a/src/ldDocument.cpp	Sat Sep 05 23:55:06 2015 +0300
+++ b/src/ldDocument.cpp	Sun Sep 06 01:22:25 2015 +0300
@@ -30,6 +30,7 @@
 #include "glCompiler.h"
 #include "partDownloader.h"
 #include "ldpaths.h"
+#include "documentloader.h"
 #include "dialogs/openprogressdialog.h"
 
 ConfigOption (QStringList RecentFiles)
@@ -37,7 +38,6 @@
 
 static bool g_loadingMainFile = false;
 enum { MAX_RECENT_FILES = 10 };
-static bool g_aborted = false;
 static LDDocument* g_logoedStud;
 static LDDocument* g_logoedStud2;
 static bool g_loadingLogoedStuds = false;
@@ -329,140 +329,15 @@
 
 // =============================================================================
 //
-void LDFileLoader::start()
-{
-	setDone (false);
-	setProgress (0);
-	setAborted (false);
-
-	if (isOnForeground())
-	{
-		g_aborted = false;
-
-		// Show a progress dialog if we're loading the main ldDocument.here so we can
-		// show progress updates and keep the WM posted that we're still here.
-		// Of course we cannot exec() the dialog because then the dialog would
-		// block.
-		dlg = new OpenProgressDialog (g_win);
-		dlg->setNumLines (lines().size());
-		dlg->setModal (true);
-		dlg->show();
-
-		// Connect the loader in so we can show updates
-		connect (this, SIGNAL (workDone()), dlg, SLOT (accept()));
-		connect (dlg, SIGNAL (rejected()), this, SLOT (abort()));
-	}
-	else
-		dlg = null;
-
-	// Begin working
-	work (0);
-}
-
-// =============================================================================
-//
-void LDFileLoader::work (int i)
-{
-	// User wishes to abort, so stop here now.
-	if (isAborted())
-	{
-		for (LDObject* obj : m_objects)
-			obj->destroy();
-
-		m_objects.clear();
-		setDone (true);
-		return;
-	}
-
-	// Parse up to 300 lines per iteration
-	int max = i + 300;
-
-	for (; i < max and i < (int) lines().size(); ++i)
-	{
-		QString line = lines()[i];
-
-		// Trim the trailing newline
-		QChar c;
-
-		while (line.endsWith ("\n") or line.endsWith ("\r"))
-			line.chop (1);
-
-		LDObject* obj = ParseLine (line);
-
-		// Check for parse errors and warn about tthem
-		if (obj->type() == OBJ_Error)
-		{
-			print ("Couldn't parse line #%1: %2",
-				progress() + 1, static_cast<LDError*> (obj)->reason());
-
-			if (warnings() != null)
-				(*warnings())++;
-		}
-
-		m_objects << obj;
-		setProgress (i);
-
-		// If we have a dialog pointer, update the progress now
-		if (dlg)
-			dlg->setProgress (i);
-	}
-
-	// If we're done now, tell the environment we're done and stop.
-	if (i >= ((int) lines().size()) - 1)
-	{
-		emit workDone();
-		setDone (true);
-		return;
-	}
-
-	// Otherwise, continue, by recursing back.
-	if (not isDone())
-	{
-		// If we have a dialog to show progress output to, we cannot just call
-		// work() again immediately as the dialog needs some processor cycles as
-		// well. Thus, take a detour through the event loop by using the
-		// meta-object system.
-		//
-		// This terminates the loop here and control goes back to the function
-		// which called the file loader. It will keep processing the event loop
-		// until we're ready (see loadFileContents), thus the event loop will
-		// eventually catch the invokation we throw here and send us back. Though
-		// it's not technically recursion anymore, more like a for loop. :P
-		if (isOnForeground())
-			QMetaObject::invokeMethod (this, "work", Qt::QueuedConnection, Q_ARG (int, i));
-		else
-			work (i);
-	}
-}
-
-// =============================================================================
-//
-void LDFileLoader::abort()
-{
-	setAborted (true);
-
-	if (isOnForeground())
-		g_aborted = true;
-}
-
-// =============================================================================
-//
 LDObjectList LoadFileContents (QFile* fp, int* numWarnings, bool* ok)
 {
-	QStringList lines;
 	LDObjectList objs;
 
 	if (numWarnings)
 		*numWarnings = 0;
 
-	// Read in the lines
-	while (not fp->atEnd())
-		lines << QString::fromUtf8 (fp->readLine());
-
-	LDFileLoader* loader = new LDFileLoader;
-	loader->setWarnings (numWarnings);
-	loader->setLines (lines);
-	loader->setOnForeground (g_loadingMainFile);
+	DocumentLoader* loader = new DocumentLoader (g_loadingMainFile);
+	loader->read (fp);
 	loader->start();
 
 	// After start() returns, if the loader isn't done yet, it's delaying
@@ -474,7 +349,7 @@
 
 	// If we wanted the success value, supply that now
 	if (ok)
-		*ok = not loader->isAborted();
+		*ok = not loader->hasAborted();
 
 	objs = loader->objects();
 	delete loader;
@@ -483,7 +358,7 @@
 
 // =============================================================================
 //
-LDDocument* OpenDocument (QString path, bool search, bool implicit, LDDocument* fileToOverride)
+LDDocument* OpenDocument (QString path, bool search, bool implicit, LDDocument* fileToOverride, bool* aborted)
 {
 	// Convert the file name to lowercase when searching because some parts contain subfile
 	// subfile references with uppercase file names. I'll assume here that the library will always
@@ -523,6 +398,9 @@
 	fp->close();
 	fp->deleteLater();
 
+	if (aborted)
+		*aborted = ok == false;
+
 	if (not ok)
 	{
 		load->close();
@@ -669,11 +547,12 @@
 		file->clear();
 	}
 
-	file = OpenDocument (path, false, false, file);
+	bool aborted;
+	file = OpenDocument (path, false, false, file, &aborted);
 
 	if (file == null)
 	{
-		if (not g_aborted)
+		if (not aborted)
 		{
 			// Tell the user loading failed.
 			setlocale (LC_ALL, "C");
--- a/src/ldDocument.h	Sat Sep 05 23:55:06 2015 +0300
+++ b/src/ldDocument.h	Sun Sep 06 01:22:25 2015 +0300
@@ -127,7 +127,7 @@
 
 // Opens the given file and parses the LDraw code within. Returns a pointer
 // to the opened file or null on error.
-LDDocument* OpenDocument (QString path, bool search, bool implicit, LDDocument* fileToOverride = nullptr);
+LDDocument* OpenDocument (QString path, bool search, bool implicit, LDDocument* fileToOverride = nullptr, bool* aborted = nullptr);
 
 // Opens the given file and returns a pointer to it, potentially looking in /parts and /p
 QFile* OpenLDrawFile (QString relpath, bool subdirs, QString* pathpointer = null);
@@ -152,37 +152,3 @@
 void LoadLogoStuds();
 QString Basename (QString path);
 QString Dirname (QString path);
-
-// =============================================================================
-//
-// LDFileLoader
-//
-// Loads the given file and parses it to LDObjects using parseLine. It's a
-// separate class so as to be able to do the work progressively through the
-// event loop, allowing the program to maintain responsivity during loading.
-//
-class LDFileLoader : public QObject
-{
-	Q_OBJECT
-	PROPERTY (private,	LDObjectList,	objects,		setObjects,			STOCK_WRITE)
-	PROPERTY (private,	bool,			isDone,			setDone,			STOCK_WRITE)
-	PROPERTY (private,	int,			progress,		setProgress,		STOCK_WRITE)
-	PROPERTY (private,	bool,			isAborted,		setAborted,			STOCK_WRITE)
-	PROPERTY (public,	QStringList,	lines,			setLines,			STOCK_WRITE)
-	PROPERTY (public,	int*,			warnings,		setWarnings,		STOCK_WRITE)
-	PROPERTY (public,	bool,			isOnForeground,	setOnForeground,	STOCK_WRITE)
-
-	public slots:
-		void start();
-		void abort();
-
-	private:
-		OpenProgressDialog* dlg;
-
-	private slots:
-		void work (int i);
-
-	signals:
-		void progressUpdate (int progress);
-		void workDone();
-};

mercurial