Wed, 10 Jul 2013 01:40:59 +0300
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