Sun, 06 Sep 2015 01:22:25 +0300
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(); -};