From e0274af49354716632af88f387049ac38f8c9c7c Mon Sep 17 00:00:00 2001 From: James Turner Date: Thu, 19 Mar 2015 12:01:38 -0500 Subject: [PATCH] Percentage feedback during nav-cache build. - also used by the GUI launcher for the same. --- src/Airports/apt_loader.cxx | 9 ++++ src/GUI/QtLauncher.cxx | 42 ++++++++++++++++-- src/Main/fg_init.cxx | 20 +++++++-- src/Main/main.cxx | 3 -- src/Navaids/NavDataCache.cxx | 82 +++++++++++++++++++++++++++++------- src/Navaids/NavDataCache.hxx | 20 +++++++-- src/Navaids/fixlist.cxx | 14 +++++- src/Navaids/navdb.cxx | 15 ++++++- src/Navaids/poidb.cxx | 10 +++++ src/Viewer/splash.cxx | 9 +++- src/Viewer/splash.hxx | 2 +- 11 files changed, 191 insertions(+), 35 deletions(-) diff --git a/src/Airports/apt_loader.cxx b/src/Airports/apt_loader.cxx index f2f3b7120..4d159d7fc 100644 --- a/src/Airports/apt_loader.cxx +++ b/src/Airports/apt_loader.cxx @@ -67,6 +67,8 @@ static FGPositioned::Type fptypeFromRobinType(int aType) } } +// generated by 'wc -l' on the uncompressed file +const unsigned int LINES_IN_APT_DAT = 2465648; namespace flightgear { @@ -109,6 +111,12 @@ public: continue; } + if ((line_num % 100) == 0) { + // every 100 lines + unsigned int percent = (line_num * 100) / LINES_IN_APT_DAT; + cache->setRebuildPhaseProgress(NavDataCache::REBUILD_AIRPORTS, percent); + } + if (line.size() >= 3) { char *p = (char *)memchr(tmp, ' ', 3); if ( p ) @@ -557,6 +565,7 @@ bool metarDataLoad(const SGPath& metar_file) } NavDataCache* cache = NavDataCache::instance(); + string ident; while ( metar_in ) { metar_in >> ident; diff --git a/src/GUI/QtLauncher.cxx b/src/GUI/QtLauncher.cxx index 86eb19e3a..d36ca2fc5 100644 --- a/src/GUI/QtLauncher.cxx +++ b/src/GUI/QtLauncher.cxx @@ -72,18 +72,52 @@ namespace { // anonymous namespace void initNavCache() { + QString baseLabel = QT_TR_NOOP("Initialising navigation data, this may take several minutes"); NavDataCache* cache = NavDataCache::createInstance(); if (cache->isRebuildRequired()) { - QProgressDialog rebuildProgress("Initialising navigation data, this may take several minutes", + QProgressDialog rebuildProgress(baseLabel, QString() /* cancel text */, - 0, 0); + 0, 100); rebuildProgress.setWindowModality(Qt::WindowModal); rebuildProgress.show(); - while (!cache->rebuild()) { + NavDataCache::RebuildPhase phase = cache->rebuild(); + + while (phase != NavDataCache::REBUILD_DONE) { // sleep to give the rebuild thread more time SGTimeStamp::sleepForMSec(50); - rebuildProgress.setValue(0); + phase = cache->rebuild(); + + switch (phase) { + case NavDataCache::REBUILD_AIRPORTS: + rebuildProgress.setLabelText(QT_TR_NOOP("Loading airport data")); + break; + + case NavDataCache::REBUILD_FIXES: + rebuildProgress.setLabelText(QT_TR_NOOP("Loading waypoint data")); + break; + + case NavDataCache::REBUILD_NAVAIDS: + rebuildProgress.setLabelText(QT_TR_NOOP("Loading navigation data")); + break; + + + case NavDataCache::REBUILD_POIS: + rebuildProgress.setLabelText(QT_TR_NOOP("Loading point-of-interest data")); + break; + + default: + rebuildProgress.setLabelText(baseLabel); + } + + if (phase == NavDataCache::REBUILD_UNKNOWN) { + rebuildProgress.setValue(0); + rebuildProgress.setMaximum(0); + } else { + rebuildProgress.setValue(cache->rebuildPhaseCompletionPercentage()); + rebuildProgress.setMaximum(100); + } + QCoreApplication::processEvents(); } } diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx index 9604f2a59..e7b391862 100644 --- a/src/Main/fg_init.cxx +++ b/src/Main/fg_init.cxx @@ -129,7 +129,7 @@ #include #include #include - +#include #include #include "fg_init.hxx" @@ -592,9 +592,23 @@ fgInitNav () doingRebuild = cache->isRebuildRequired(); } + static const char* splashIdentsByRebuildPhase[] = { + "loading-nav-dat", + "navdata-airports", + "navdata-navaids", + "navdata-fixes", + "navdata-pois" + }; + if (doingRebuild) { - bool finished = cache->rebuild(); - if (!finished) { + flightgear::NavDataCache::RebuildPhase phase; + phase = cache->rebuild(); + if (phase != flightgear::NavDataCache::REBUILD_DONE) { + // update the splash text based on percentage, phase + + fgSplashProgress(splashIdentsByRebuildPhase[phase], + cache->rebuildPhaseCompletionPercentage()); + // sleep to give the rebuild thread more time SGTimeStamp::sleepForMSec(50); return false; diff --git a/src/Main/main.cxx b/src/Main/main.cxx index d6ab4c563..30edd654e 100644 --- a/src/Main/main.cxx +++ b/src/Main/main.cxx @@ -221,10 +221,7 @@ static void fgIdleFunction ( void ) { if (done) { ++idle_state; fgSplashProgress("init-scenery"); - } else { - fgSplashProgress("loading-nav-dat"); } - } else if ( idle_state == 4 ) { idle_state++; diff --git a/src/Navaids/NavDataCache.cxx b/src/Navaids/NavDataCache.cxx index 1a5b696ab..1746ece4e 100644 --- a/src/Navaids/NavDataCache.cxx +++ b/src/Navaids/NavDataCache.cxx @@ -162,6 +162,8 @@ class RebuildThread : public SGThread public: RebuildThread(NavDataCache* cache) : _cache(cache), + _phase(NavDataCache::REBUILD_UNKNOWN), + _completionPercent(0), _isFinished(false) { @@ -182,9 +184,36 @@ public: SGGuard g(_lock); _isFinished = true; + _phase = NavDataCache::REBUILD_DONE; } + + NavDataCache::RebuildPhase currentPhase() const + { + NavDataCache::RebuildPhase ph; + SGGuard g(_lock); + ph = _phase; + return ph; + } + + unsigned int completionPercent() const + { + unsigned int perc = 0; + SGGuard g(_lock); + perc = _completionPercent; + return perc; + } + + void setProgress(NavDataCache::RebuildPhase ph, unsigned int percent) + { + SGGuard g(_lock); + _phase = ph; + _completionPercent = percent; + } + private: NavDataCache* _cache; + NavDataCache::RebuildPhase _phase; + unsigned int _completionPercent; mutable SGMutex _lock; bool _isFinished; }; @@ -1184,21 +1213,39 @@ bool NavDataCache::dropGroundnetsIfRequired() return false; } -bool NavDataCache::rebuild() +NavDataCache::RebuildPhase NavDataCache::rebuild() { - if (!d->rebuilder.get()) { - d->rebuilder.reset(new RebuildThread(this)); - d->rebuilder->start(); - } - -// poll the rebuild thread - bool fin = d->rebuilder->isFinished(); - if (fin) { - d->rebuilder.reset(); // all done! - } - return fin; + if (!d->rebuilder.get()) { + d->rebuilder.reset(new RebuildThread(this)); + d->rebuilder->start(); + } + + // poll the rebuild thread + RebuildPhase phase = d->rebuilder->currentPhase(); + if (phase == REBUILD_DONE) { + d->rebuilder.reset(); // all done! + } + return phase; } - + +unsigned int NavDataCache::rebuildPhaseCompletionPercentage() const +{ + if (!d->rebuilder.get()) { + return 0; + } + + return d->rebuilder->completionPercent(); +} + +void NavDataCache::setRebuildPhaseProgress(RebuildPhase ph, unsigned int percent) +{ + if (!d->rebuilder.get()) { + return; + } + + d->rebuilder->setProgress(ph, percent); +} + void NavDataCache::doRebuild() { try { @@ -1216,7 +1263,8 @@ void NavDataCache::doRebuild() st.stamp(); airportDBLoad(d->aptDatPath); SG_LOG(SG_NAVCACHE, SG_INFO, "apt.dat load took:" << st.elapsedMSec()); - + + setRebuildPhaseProgress(REBUILD_UNKNOWN); metarDataLoad(d->metarDatPath); stampCacheFile(d->aptDatPath); stampCacheFile(d->metarDatPath); @@ -1230,7 +1278,8 @@ void NavDataCache::doRebuild() navDBInit(d->navDatPath); stampCacheFile(d->navDatPath); SG_LOG(SG_NAVCACHE, SG_INFO, "nav.dat load took:" << st.elapsedMSec()); - + + setRebuildPhaseProgress(REBUILD_UNKNOWN); st.stamp(); txn.commit(); SG_LOG(SG_NAVCACHE, SG_INFO, "stage 1 commit took:" << st.elapsedMSec()); @@ -1246,7 +1295,8 @@ void NavDataCache::doRebuild() poiDBInit(d->poiDatPath); stampCacheFile(d->poiDatPath); SG_LOG(SG_NAVCACHE, SG_INFO, "poi.dat load took:" << st.elapsedMSec()); - + + setRebuildPhaseProgress(REBUILD_UNKNOWN); st.stamp(); txn.commit(); SG_LOG(SG_NAVCACHE, SG_INFO, "POI commit took:" << st.elapsedMSec()); diff --git a/src/Navaids/NavDataCache.hxx b/src/Navaids/NavDataCache.hxx index 47220d073..5c8bbbc8a 100644 --- a/src/Navaids/NavDataCache.hxx +++ b/src/Navaids/NavDataCache.hxx @@ -76,12 +76,24 @@ public: */ bool dropGroundnetsIfRequired(); + enum RebuildPhase + { + REBUILD_UNKNOWN = 0, + REBUILD_AIRPORTS, + REBUILD_NAVAIDS, + REBUILD_FIXES, + REBUILD_POIS, + REBUILD_DONE + }; + /** - * run the cache rebuild - returns true if rebuild is complete, - * otherwise keep going. + * run the cache rebuild - returns the current phase or 'done' */ - bool rebuild(); - + RebuildPhase rebuild(); + + unsigned int rebuildPhaseCompletionPercentage() const; + void setRebuildPhaseProgress(RebuildPhase ph, unsigned int percent = 0); + bool isCachedFileModified(const SGPath& path) const; void stampCacheFile(const SGPath& path); diff --git a/src/Navaids/fixlist.cxx b/src/Navaids/fixlist.cxx index 27ece5744..c665b1de1 100644 --- a/src/Navaids/fixlist.cxx +++ b/src/Navaids/fixlist.cxx @@ -45,6 +45,8 @@ FGFix::FGFix(PositionedID aGuid, const std::string& aIdent, const SGGeod& aPos) namespace flightgear { + +const unsigned int LINES_IN_FIX_DAT = 119724; void loadFixes(const SGPath& path) { @@ -58,7 +60,8 @@ void loadFixes(const SGPath& path) in >> skipeol; NavDataCache* cache = NavDataCache::instance(); - + unsigned int lineNumber = 2; + // read in each remaining line of the file while ( ! in.eof() ) { double lat, lon; @@ -68,8 +71,15 @@ void loadFixes(const SGPath& path) cache->insertFix(ident, SGGeod::fromDeg(lon, lat)); in >> skipcomment; + + ++lineNumber; + if ((lineNumber % 100) == 0) { + // every 100 lines + unsigned int percent = (lineNumber * 100) / LINES_IN_FIX_DAT; + cache->setRebuildPhaseProgress(NavDataCache::REBUILD_FIXES, percent); + } } } - + } // of namespace flightgear; diff --git a/src/Navaids/navdb.cxx b/src/Navaids/navdb.cxx index 4b01c3ad6..964d2b3cc 100644 --- a/src/Navaids/navdb.cxx +++ b/src/Navaids/navdb.cxx @@ -251,6 +251,9 @@ static PositionedID readNavFromStream(std::istream& aStream, return r; } + +// generated by wc -l on uncomrpessed nav.dat +const unsigned int LINES_IN_NAV_DAT = 26775; // load and initialize the navigational databases bool navDBInit(const SGPath& path) @@ -260,17 +263,27 @@ bool navDBInit(const SGPath& path) SG_LOG( SG_NAVAID, SG_ALERT, "Cannot open file: " << path.str() ); return false; } - + autoAlignLocalizers = fgGetBool("/sim/navdb/localizers/auto-align", true); autoAlignThreshold = fgGetDouble( "/sim/navdb/localizers/auto-align-threshold-deg", 5.0 ); + NavDataCache* cache = NavDataCache::instance(); // skip first two lines in >> skipeol; in >> skipeol; + unsigned int lineNumber = 2; while (!in.eof()) { readNavFromStream(in); in >> skipcomment; + + ++lineNumber; + if ((lineNumber % 100) == 0) { + // every 100 lines + unsigned int percent = (lineNumber * 100) / LINES_IN_NAV_DAT; + cache->setRebuildPhaseProgress(NavDataCache::REBUILD_NAVAIDS, percent); + } + } // of stream data loop return true; diff --git a/src/Navaids/poidb.cxx b/src/Navaids/poidb.cxx index 15da16813..8782f85d0 100644 --- a/src/Navaids/poidb.cxx +++ b/src/Navaids/poidb.cxx @@ -52,6 +52,8 @@ mapPOITypeToFGPType(int aTy) namespace flightgear { + const int LINES_IN_POI_DAT = 769019; + static PositionedID readPOIFromStream(std::istream& aStream, NavDataCache* cache, FGPositioned::Type type = FGPositioned::INVALID) { @@ -96,9 +98,17 @@ bool poiDBInit(const SGPath& path) return false; } + unsigned int lineNumber = 0; NavDataCache* cache = NavDataCache::instance(); while (!in.eof()) { readPOIFromStream(in, cache); + + ++lineNumber; + if ((lineNumber % 100) == 0) { + // every 100 lines + unsigned int percent = (lineNumber * 100) / LINES_IN_POI_DAT; + cache->setRebuildPhaseProgress(NavDataCache::REBUILD_POIS, percent); + } } // of stream data loop return true; diff --git a/src/Viewer/splash.cxx b/src/Viewer/splash.cxx index 03995c44f..99539c735 100644 --- a/src/Viewer/splash.cxx +++ b/src/Viewer/splash.cxx @@ -385,7 +385,7 @@ void fgSplashInit () { globals->get_renderer()->splashinit(); } -void fgSplashProgress( const char *identifier ) { +void fgSplashProgress( const char *identifier, unsigned int percent ) { const char* spinChars = "-\\|/"; static int spin_count = 0; std::string spin_status = std::string(""); @@ -415,6 +415,13 @@ void fgSplashProgress( const char *identifier ) { fgSetString("/sim/startup/splash-progress-text", oss.str()); return; } + + // over-write the spinner + if (!strncmp(identifier, "navdata-", 8)) { + std::ostringstream oss; + oss << percent << "% complete"; + fgSetString("/sim/startup/splash-progress-spinner", oss.str()); + } if( fgGetString("/sim/startup/splash-progress-text") == text ) return; diff --git a/src/Viewer/splash.hxx b/src/Viewer/splash.hxx index d6c054dfb..cb1c219c5 100644 --- a/src/Viewer/splash.hxx +++ b/src/Viewer/splash.hxx @@ -36,7 +36,7 @@ void fgSplashInit (); /** Set progress information. * "identifier" references an element of the language resource. */ -void fgSplashProgress ( const char *identifier ); +void fgSplashProgress ( const char *identifier, unsigned int percent = 0 ); /** Retrieve the splash screen node */ osg::Node* fgCreateSplashNode();