make file loading be done properly as just a QObject rather than multi-threaded..

Wed, 10 Jul 2013 01:40:59 +0300

author
Santeri Piippo <crimsondusk64@gmail.com>
date
Wed, 10 Jul 2013 01:40:59 +0300
changeset 370
843b3dbbd849
parent 369
0060d11e4991
child 371
e8ef9fb4721b

make file loading be done properly as just a QObject rather than multi-threaded..

src/dialogs.cpp file | annotate | diff | comparison | revisions
src/dialogs.h file | annotate | diff | comparison | revisions
src/extprogs.h file | annotate | diff | comparison | revisions
src/file.cpp file | annotate | diff | comparison | revisions
src/file.h file | annotate | diff | comparison | revisions
--- a/src/dialogs.cpp	Tue Jul 09 03:07:39 2013 +0300
+++ b/src/dialogs.cpp	Wed Jul 10 01:40:59 2013 +0300
@@ -37,6 +37,7 @@
 #include "dialogs.h"
 #include "ui_overlay.h"
 #include "ui_ldrawpath.h"
+#include "ui_openprogress.h"
 
 extern_cfg (str, io_ldpath);
 
@@ -229,38 +230,41 @@
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-OpenProgressDialog::OpenProgressDialog (QWidget* parent, Qt::WindowFlags f) : QDialog (parent, f) {
-	progressBar = new QProgressBar;
-	progressText = new QLabel( "Parsing..." );
-	setNumLines (0);
-	m_progress = 0;
+OpenProgressDialog::OpenProgressDialog( QWidget* parent, Qt::WindowFlags f ) : QDialog( parent, f )
+{
+	ui = new Ui_OpenProgressUI;
+	ui->setupUi( this );
+	ui->progressText->setText( "Parsing..." );
 	
-	QDialogButtonBox* dbb_buttons = new QDialogButtonBox;
-	dbb_buttons->addButton (QDialogButtonBox::Cancel);
-	connect (dbb_buttons, SIGNAL (rejected ()), this, SLOT (reject ()));
-	
-	QVBoxLayout* layout = new QVBoxLayout (this);
-	layout->addWidget (progressText);
-	layout->addWidget (progressBar);
-	layout->addWidget (dbb_buttons);
+	setNumLines( 0 );
+	m_progress = 0;
 }
 
-READ_ACCESSOR (ulong, OpenProgressDialog::numLines) {
+OpenProgressDialog::~OpenProgressDialog()
+{
+	delete ui;
+}
+
+READ_ACCESSOR( ulong, OpenProgressDialog::numLines )
+{
 	return m_numLines;
 }
 
-SET_ACCESSOR (ulong, OpenProgressDialog::setNumLines) {
+SET_ACCESSOR( ulong, OpenProgressDialog::setNumLines )
+{
 	m_numLines = val;
-	progressBar->setRange (0, numLines ());
-	updateValues ();
+	ui->progressBar->setRange (0, numLines ());
+	updateValues();
 }
 
-void OpenProgressDialog::updateValues () {
-	progressText->setText( fmt( "Parsing... %1 / %2", progress(), numLines() ));
-	progressBar->setValue( progress() );
+void OpenProgressDialog::updateValues()
+{
+	ui->progressText->setText( fmt( "Parsing... %1 / %2", progress(), numLines() ));
+	ui->progressBar->setValue( progress() );
 }
 
-void OpenProgressDialog::updateProgress (int progress) {
+void OpenProgressDialog::updateProgress( int progress )
+{
 	m_progress = progress;
 	updateValues ();
 }
\ No newline at end of file
--- a/src/dialogs.h	Tue Jul 09 03:07:39 2013 +0300
+++ b/src/dialogs.h	Wed Jul 10 01:40:59 2013 +0300
@@ -38,6 +38,7 @@
 class QAbstractButton;
 class Ui_OverlayUI;
 class Ui_LDPathUI;
+class Ui_OpenProgressUI;
 
 class OverlayDialog : public QDialog
 {
@@ -90,20 +91,21 @@
 };
 
 // =============================================================================
-class OpenProgressDialog : public QDialog {
+class OpenProgressDialog : public QDialog
+{
 	Q_OBJECT
-	READ_PROPERTY (ulong, progress, setProgress)
-	DECLARE_PROPERTY (ulong, numLines, setNumLines)
+	READ_PROPERTY( ulong, progress, setProgress )
+	DECLARE_PROPERTY( ulong, numLines, setNumLines )
 	
 public:
-	explicit OpenProgressDialog (QWidget* parent = null, Qt::WindowFlags f = 0);
+	explicit OpenProgressDialog( QWidget* parent = null, Qt::WindowFlags f = 0 );
+	virtual ~OpenProgressDialog();
 	
 public slots:
 	void updateProgress (int progress);
 	
 private:
-	QProgressBar* progressBar;
-	QLabel* progressText;
+	Ui_OpenProgressUI* ui;
 	
 	void updateValues ();
 };
--- a/src/extprogs.h	Tue Jul 09 03:07:39 2013 +0300
+++ b/src/extprogs.h	Wed Jul 10 01:40:59 2013 +0300
@@ -21,7 +21,8 @@
 
 #include <qobject.h>
 
-enum extprog {
+enum extprog
+{
 	Isecalc,
 	Intersector,
 	Coverer,
--- a/src/file.cpp	Tue Jul 09 03:07:39 2013 +0300
+++ b/src/file.cpp	Wed Jul 10 01:40:59 2013 +0300
@@ -18,9 +18,8 @@
 
 #include <QMessageBox>
 #include <QFileDialog>
-#include <qprogressbar.h>
 #include <QDir>
-#include <QThread>
+#include <QApplication>
 
 #include <stdlib.h>
 #include "common.h"
@@ -45,16 +44,13 @@
 {
 	static str pathError;
 	
-	struct
-	{
+	struct {
 		str LDConfigPath;
 		str partsPath, primsPath;
 	} pathInfo;
 	
-	void initPaths ()
-	{
-		if( !tryConfigure ( io_ldpath ))
-		{
+	void initPaths() {
+		if( !tryConfigure( io_ldpath )) {
 			LDrawPathDialog dlg (false);
 			
 			if( !dlg.exec () )
@@ -64,12 +60,10 @@
 		}
 	}
 	
-	bool tryConfigure( str path )
-	{
+	bool tryConfigure( str path ) {
 		QDir dir;
 		
-		if( !dir.cd( path ))
-		{
+		if( !dir.cd( path )) {
 			pathError = "Directory does not exist.";
 			return false;
 		}
@@ -77,7 +71,7 @@
 		QStringList mustHave = { "LDConfig.ldr", "parts", "p" };
 		QStringList contents = dir.entryList( mustHave );
 		
-		if (contents.size () != mustHave.size ()) {
+		if( contents.size() != mustHave.size() ) {
 			pathError = "Not an LDraw directory! Must<br />have LDConfig.ldr, parts/ and p/.";
 			return false;
 		}
@@ -155,6 +149,7 @@
 File* openLDrawFile (str relpath, bool subdirs) {
 	print( "%1: Try to open %2\n", __func__, relpath );
 	File* f = new File;
+	str fullPath;
 	
 	// LDraw models use Windows-style path separators. If we're not on Windows,
 	// replace the path separator now before opening any files.
@@ -162,43 +157,34 @@
 	relpath.replace( "\\", "/" );
 #endif // WIN32
 	
-	if( g_curfile )
-	{
+	if( g_curfile ) {
 		// First, try find the file in the current model's file path. We want a file
 		// in the immediate vicinity of the current model to override stock LDraw stuff.
 		str partpath = fmt ("%1" DIRSLASH "%2", dirname (g_curfile->name ()), relpath);
 		
-		if (f->open (partpath, File::Read))
-			return f;
-	}
+		if (f->open (partpath, File::Read)) {
+			return f; }}
 	
 	if (f->open (relpath, File::Read))
 		return f;
 	
-	str fullPath;
-	if( io_ldpath.value.length() > 0 )
-	{
-		// Try with just the LDraw path first
-		fullPath = fmt ("%1" DIRSLASH "%2", io_ldpath, relpath);
-		
-		if( f->open( fullPath, File::Read ))
-			return f;
-		
-		if( subdirs )
-		{
-			// Look in sub-directories: parts and p
-			for( auto subdir : initlist<const str>({ "parts", "p" }))
-			{
-				fullPath = fmt ("%1" DIRSLASH "%2" DIRSLASH "%3",
-					io_ldpath, subdir, relpath);
-				
-				if (f->open (fullPath, File::Read))
-					return f;
-			}
-		}
-	}
+	// Try with just the LDraw path first
+	fullPath = fmt ("%1" DIRSLASH "%2", io_ldpath, relpath);
+	
+	if( f->open( fullPath, File::Read ))
+		return f;
+	
+	if( subdirs ) {
+		// Look in sub-directories: parts and p
+		for( auto subdir : initlist<const str>({ "parts", "p" })) {
+			fullPath = fmt ("%1" DIRSLASH "%2" DIRSLASH "%3",
+				io_ldpath, subdir, relpath);
+			
+			if (f->open (fullPath, File::Read))
+				return f; }}
 	
 	// Did not find the file.
+	print( "could not find %1\n", relpath );
 	delete f;
 	return null;
 }
@@ -206,13 +192,46 @@
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-void FileLoader::work()
-{
+void FileLoader::start() {
 	setDone( false );
 	setProgress( 0 );
 	abortflag = false;
 	
-	for( str line : *PROP_NAME( file )) {
+	if( concurrent() ) {
+		// Show a progress dialog if we're loading the main file here and move
+		// the actual work to a separate thread as this can be a rather intensive
+		// operation and if we don't respond quickly enough, the program can be
+		// deemed inresponsive.. which is a bad thing.
+		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() )); }
+	else
+		dlg = null;
+	
+	work( 0 );
+}
+
+void FileLoader::work( ulong i ) {
+	print( "%1: %2\n", this, i );
+	
+	if( abortflag ) {
+		// We were flagged for abortion, so abort.
+		for( LDObject* obj : m_objs )
+			delete obj;
+		
+		m_objs.clear();
+		abortflag = false;
+		return;
+	}
+	
+	ulong max = i + 300;
+	for( ; i < max && i < lines().size(); ++i ) {
+		str line = lines()[i];
+		
 		// Trim the trailing newline
 		qchar c;
 		while(( c = line[line.length () - 1] ) == '\n' || c == '\r' )
@@ -221,32 +240,29 @@
 		LDObject* obj = parseLine( line );
 		
 		// Check for parse errors and warn about tthem
-		if( obj->getType () == LDObject::Gibberish )
-		{
+		if( obj->getType () == LDObject::Gibberish ) {
 			log( "Couldn't parse line #%1: %2", m_progress + 1, static_cast<LDGibberish*> (obj)->reason );
-			log( "- Line was: %1", line );
 			
-			if( m_warningsPointer )
-				( *m_warningsPointer )++;
-		}
+			if( m_warningsPointer ) {
+				( *m_warningsPointer )++; }}
 		
 		m_objs << obj;
-		m_progress++;
-		emit progressUpdate( m_progress );
+		setProgress( i );
 		
-		if( abortflag )
-		{
-			// We were flagged for abortion, so abort.
-			for( LDObject* obj : m_objs )
-				delete obj;
-			
-			m_objs.clear();
-			return;
-		}
+		if( concurrent() )
+			dlg->updateProgress( i );
 	}
 	
-	emit workDone();
-	m_done = true;
+	if( i >= lines().size() - 1 ) {
+		emit workDone();
+		setDone( true ); }
+	
+	if( !done() ) {
+		if( concurrent() )
+			QMetaObject::invokeMethod( this, "work", Qt::QueuedConnection, Q_ARG( ulong, i + 1 ));
+		else
+			work( i + 1 );
+	}
 }
 
 // =============================================================================
@@ -260,56 +276,25 @@
 	if( numWarnings )
 		*numWarnings = 0;
 	
-	FileLoader* loader = new FileLoader;
-	loader->setFile( f );
-	loader->setWarningsPointer( numWarnings );
-	
 	// Calculate the amount of lines
-	ulong numLines = 0;
 	for( str line : *f )
-		numLines++;
-	
+		lines << line;
 	f->rewind();
 	
-	if (g_loadingMainFile)
-	{
-		// Show a progress dialog if we're loading the main file here and move
-		// the actual work to a separate thread as this can be a rather intensive
-		// operation and if we don't respond quickly enough, the program can be
-		// deemed inresponsive.. which is a bad thing.
-		
-		// Init the thread and move the loader into it
-		QThread* loaderThread = new QThread;
-		QObject::connect( loaderThread, SIGNAL( started() ), loader, SLOT( work() ));
-		QObject::connect( loaderThread, SIGNAL( finished() ), loader, SLOT( deleteLater() ));
-		loader->moveToThread (loaderThread);
-		loaderThread->start ();
-		
-		// Now create a progress prompt for the operation
-		OpenProgressDialog* dlg = new OpenProgressDialog (g_win);
-		dlg->setNumLines( numLines );
-		
-		// Connect the loader in so we can show updates
-		QObject::connect( loader, SIGNAL( progressUpdate( int )), dlg, SLOT( updateProgress( int )));
-		QObject::connect( loader, SIGNAL( workDone() ), dlg, SLOT( accept() ));
-		
-		// Show the prompt. If the user hits cancel, tell the loader to abort.
-		if( !dlg->exec() )
-		{
-			loader->abortflag = true;
-			g_aborted = true;
-		}
-	} else
-		loader->work();
+	FileLoader* loader = new FileLoader;
+	loader->setWarningsPointer( numWarnings );
+	loader->setLines( lines );
+	loader->setConcurrent( g_loadingMainFile );
+	loader->start();
+	
+	while( loader->done() == false )
+		qApp->processEvents();
 	
 	// If we wanted the success value, supply that now
 	if( ok )
 		*ok = loader->done();
 	
-	// If the loader was done, return the objects it generated
-	if( loader->done() )
-		objs = loader->objs();
-	
+	objs = loader->objs();
 	return objs;
 }
 
@@ -327,12 +312,9 @@
 	else {
 		f = new File( path, File::Read );
 		
-		if( !*f )
-		{
+		if( !*f ) {
 			delete f;
-			f = null;
-		}
-	}
+			return null; }}
 	
 	if( !f )
 		return null;
@@ -786,14 +768,14 @@
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-LDOpenFile* getFile( str fname )
+LDOpenFile* getFile( str filename )
 {
 	// Try find the file in the list of loaded files
-	LDOpenFile* load = findLoadedFile( fname );
+	LDOpenFile* load = findLoadedFile( filename );
 	
 	// If it's not loaded, try open it
 	if( !load )
-		load = openDATFile( fname, true );
+		load = openDATFile( filename, true );
 	
 	return load;
 }
--- a/src/file.h	Tue Jul 09 03:07:39 2013 +0300
+++ b/src/file.h	Wed Jul 10 01:40:59 2013 +0300
@@ -88,58 +88,58 @@
 	
 	LDOpenFile& operator<<( vector<LDObject*> objs );
 	
-	it begin () { return PROP_NAME (objs).begin (); }
-	c_it begin () const { return PROP_NAME (objs).begin (); }
-	it end () { return PROP_NAME (objs).end (); }
-	c_it end () const { return PROP_NAME (objs).end (); }
+	it begin () { return PROP_NAME( objs ).begin(); }
+	c_it begin () const { return PROP_NAME( objs ).begin(); }
+	it end () { return PROP_NAME( objs ).end(); }
+	c_it end () const { return PROP_NAME( objs ).end(); }
 	
 	static void closeUnused ();
 	
-	void openHistory () { m_history.open (); }
-	void closeHistory () { m_history.close (); }
-	void undo () { m_history.undo (); }
-	void redo () { m_history.redo (); }
-	void clearHistory () { m_history.clear (); }
-	void addToHistory (AbstractHistoryEntry* entry) { m_history << entry; }
+	void openHistory() { m_history.open (); }
+	void closeHistory() { m_history.close (); }
+	void undo() { m_history.undo (); }
+	void redo() { m_history.redo (); }
+	void clearHistory() { m_history.clear (); }
+	void addToHistory( AbstractHistoryEntry* entry ) { m_history << entry; }
 };
 
 // Close all current loaded files and start off blank.
-void newFile ();
+void newFile();
 
 // Opens the given file as the main file. Everything is closed first.
-void openMainFile (str zPath);
+void openMainFile( str path );
 
 // Finds an OpenFile by name or null if not open
-LDOpenFile* findLoadedFile (str name);
+LDOpenFile* findLoadedFile( str name );
 
 // Opens the given file and parses the LDraw code within. Returns a pointer
 // to the opened file or null on error.
-LDOpenFile* openDATFile (str path, bool search);
+LDOpenFile* openDATFile( str path, bool search );
 
 // Opens the given file and returns a pointer to it, potentially looking in /parts and /p
-File* openLDrawFile (str relpath, bool subdirs);
+File* openLDrawFile( str relpath, bool subdirs );
 
 // Close all open files, whether user-opened or subfile caches.
-void closeAll ();
+void closeAll();
 
 // Parses a string line containing an LDraw object and returns the object parsed.
-LDObject* parseLine (str line);
+LDObject* parseLine( str line );
 
 // Retrieves the pointer to - or loads - the given subfile.
-LDOpenFile* getFile (str zFile);
+LDOpenFile* getFile( str filename );
 
 // Re-caches all subfiles.
-void reloadAllSubfiles ();
+void reloadAllSubfiles();
 
 // Is it safe to close all files?
-bool safeToCloseAll ();
+bool safeToCloseAll();
 
-vector<LDObject*> loadFileContents (File* f, ulong* numWarnings, bool* ok = null);
+vector<LDObject*> loadFileContents( File* f, ulong* numWarnings, bool* ok = null );
 
 extern vector<LDOpenFile*> g_loadedFiles;
 
-str basename (str path);
-str dirname (str path);
+str basename( str path );
+str dirname( str path );
 
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
@@ -151,22 +151,26 @@
 // =============================================================================
 class FileLoader : public QObject {
 	Q_OBJECT
-	
-	READ_PROPERTY (vector<LDObject*>, objs, setObjects)
-	READ_PROPERTY (bool, done, setDone)
-	READ_PROPERTY (ulong, progress, setProgress)
-	PROPERTY (File*, file, setFile)
-	PROPERTY (ulong*, warningsPointer, setWarningsPointer)
+	READ_PROPERTY( vector<LDObject*>, objs, setObjects )
+	READ_PROPERTY( bool, done, setDone )
+	READ_PROPERTY( ulong, progress, setProgress )
+	PROPERTY( vector<str>, lines, setLines )
+	PROPERTY( ulong*, warningsPointer, setWarningsPointer )
+	PROPERTY( bool, concurrent, setConcurrent )
 	
 public:
 	bool abortflag;
+	void start();
 	
-public slots:
-	void work ();
+private:
+	OpenProgressDialog* dlg;
+	
+private slots:
+	void work( ulong i );
 	
 signals:
-	void progressUpdate (int progress);
-	void workDone ();
+	void progressUpdate( int progress );
+	void workDone();
 };
 
 #endif // FILE_H
\ No newline at end of file

mercurial