From 4087d63d9c3141118725e36edb700f0454bcde7f Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Fri, 11 Mar 2016 04:13:56 +0100 Subject: [PATCH] refs #619, change model loader to use caches (one per simulator) * removed caching from GUI component * added caches in model loader * adjusted samples --- samples/blackmiscsim/samplesfscommon.cpp | 7 +- samples/blackmiscsim/samplesmodelmapping.cpp | 4 +- .../components/dbmappingcomponent.cpp | 31 ++--- src/blackgui/components/dbmappingcomponent.h | 4 - src/blackmisc/blackmisc.pro | 2 + .../simulation/aircraftmodelloader.cpp | 61 ++++++++- .../simulation/aircraftmodelloader.h | 58 ++++++-- src/blackmisc/simulation/data/modelcaches.h | 67 ++++++++++ .../simulation/fscommon/aircraftcfgparser.cpp | 126 +++++++++++++----- .../simulation/fscommon/aircraftcfgparser.h | 46 +++---- .../xplane/aircraftmodelloaderxplane.cpp | 62 +++++---- .../xplane/aircraftmodelloaderxplane.h | 35 ++--- .../simulator/fscommon/simulatorfscommon.cpp | 2 +- 13 files changed, 354 insertions(+), 151 deletions(-) create mode 100644 src/blackmisc/simulation/data/modelcaches.h diff --git a/samples/blackmiscsim/samplesfscommon.cpp b/samples/blackmiscsim/samplesfscommon.cpp index 67f35c865..d5f9e9117 100644 --- a/samples/blackmiscsim/samplesfscommon.cpp +++ b/samples/blackmiscsim/samplesfscommon.cpp @@ -15,6 +15,8 @@ #include "blackmisc/simulation/fscommon/aircraftcfgentrieslist.h" #include "blackmisc/simulation/fscommon/aircraftcfgparser.h" #include "blackmisc/simulation/aircraftmatcher.h" +#include "blackmisc/simulation/simulatorinfo.h" + #include #include @@ -24,16 +26,17 @@ #include using namespace BlackMisc; +using namespace BlackMisc::Simulation; using namespace BlackMisc::Simulation::FsCommon; namespace BlackSample { void CSamplesFsCommon::samples(QTextStream &streamOut, QTextStream &streamIn) { - QString fsxDir = CSampleUtils::selectDirectory({"C:/Program Files (x86)/Microsoft Games/Microsoft Flight Simulator X/SimObjects", + const QString fsxDir = CSampleUtils::selectDirectory({"C:/Program Files (x86)/Microsoft Games/Microsoft Flight Simulator X/SimObjects", "C:/Flight Simulator 9/Aircraft"}, streamOut, streamIn); - CAircraftCfgParser parser; + CAircraftCfgParser parser(CSimulatorInfo(CSimulatorInfo::FSX), fsxDir); parser.changeRootDirectory(fsxDir); streamOut << "start reading, press RETURN" << endl; diff --git a/samples/blackmiscsim/samplesmodelmapping.cpp b/samples/blackmiscsim/samplesmodelmapping.cpp index 1fc686889..cdfefc5c1 100644 --- a/samples/blackmiscsim/samplesmodelmapping.cpp +++ b/samples/blackmiscsim/samplesmodelmapping.cpp @@ -43,12 +43,12 @@ namespace BlackSample streamOut << "loaded: " << BlackMisc::boolToYesNo(s) << " size: " << cvm->getDatastoreModels().size() << endl; // mapper with rule set, handing over ownership - CAircraftCfgParser cfgParser; QString fsxDir = CSampleUtils::selectDirectory({QStringLiteral("P:/FlightSimulatorX (MSI)/SimObjects"), QStringLiteral("P:/Temp/SimObjects"), QStringLiteral("C:/Flight Simulator 9/Aircraft") }, streamOut, streamIn); + CAircraftCfgParser cfgParser(CSimulatorInfo(CSimulatorInfo::FSX), fsxDir); if (!cfgParser.changeRootDirectory(fsxDir)) { streamOut << "Wrong or empty directoy " << fsxDir << endl; @@ -56,7 +56,7 @@ namespace BlackSample } streamOut << "Start reading models" << endl; - cfgParser.startLoading(CAircraftCfgParser::ModeBlocking); + cfgParser.startLoading(CAircraftCfgParser::CacheSkipped | CAircraftCfgParser::LoadDirectly); streamOut << "Read models: " << cfgParser.getAircraftCfgEntriesList().size() << endl; streamOut << "Ambigious models: " << cfgParser.getAircraftCfgEntriesList().detectAmbiguousTitles().join(", ") << endl; diff --git a/src/blackgui/components/dbmappingcomponent.cpp b/src/blackgui/components/dbmappingcomponent.cpp index 3de753460..3b24884b3 100644 --- a/src/blackgui/components/dbmappingcomponent.cpp +++ b/src/blackgui/components/dbmappingcomponent.cpp @@ -68,7 +68,10 @@ namespace BlackGui ui->tvp_OwnAircraftModels->setCustomMenu(new CShowSimulatorFile(this), false); ui->tvp_OwnAircraftModels->setCustomMenu(new CMappingOwnSimulatorModelMenu(this)); ui->tvp_OwnAircraftModels->setCustomMenu(new CModelStashTools(this, false)); - ui->tvp_OwnAircraftModels->updateContainerMaybeAsync(this->m_cachedOwnModels.get()); + if (this->m_modelLoader) + { + ui->tvp_OwnAircraftModels->updateContainerMaybeAsync(this->m_modelLoader->getAircraftModels()); + } // how to display forms ui->editor_AircraftIcao->setSelectOnly(); @@ -107,9 +110,9 @@ namespace BlackGui this->ui->tvp_AircraftModelsForVPilot->setCustomMenu(new CModelStashTools(this, false)); this->ui->tvp_AircraftModelsForVPilot->setDisplayAutomatically(true); this->ui->tvp_AircraftModelsForVPilot->addFilterDialog(); - const CAircraftModelList cachedModels(m_cachedVPilotModels.get()); - this->ui->tvp_AircraftModelsForVPilot->updateContainerMaybeAsync(cachedModels); - int noModels = cachedModels.size(); + const CAircraftModelList vPilotModels(m_cachedVPilotModels.get()); + this->ui->tvp_AircraftModelsForVPilot->updateContainerMaybeAsync(vPilotModels); + int noModels = vPilotModels.size(); CLogMessage(this).info("%1 cached vPilot models loaded") << noModels; } this->m_vPilot1stInit = false; @@ -264,7 +267,8 @@ namespace BlackGui CAircraftModel CDbMappingComponent::getOwnModelForModelString(const QString &modelString) const { - return m_cachedOwnModels.get().findFirstByModelString(modelString); + if (!this->m_modelLoader) { return CAircraftModel(); } + return this->m_modelLoader->getAircraftModels().findFirstByModelString(modelString); } CDbMappingComponent::TabIndex CDbMappingComponent::currentTabIndex() const @@ -510,8 +514,9 @@ namespace BlackGui void CDbMappingComponent::ps_requestOwnModelsUpdate() { + if (!this->m_modelLoader) { return; } this->ui->tvp_OwnAircraftModels->updateContainerMaybeAsync( - this->m_cachedOwnModels.get() + this->m_modelLoader->getAircraftModels() ); } @@ -678,11 +683,7 @@ namespace BlackGui { const CAircraftModelList models(this->m_modelLoader->getAircraftModels()); CLogMessage(this).info("Loading %1 of models completed") << models.size(); - this->m_cachedOwnModels.set(models); - CLogMessage(this).info("Written %1 own models to cache") << models.size(); - - // when the cache writting is done the view vill be updated in the - // cache changed slot + this->ui->tvp_OwnAircraftModels->updateContainerMaybeAsync(models); } else { @@ -692,14 +693,6 @@ namespace BlackGui this->ui->tvp_OwnAircraftModels->hideLoadIndicator(); } - void CDbMappingComponent::ps_ownModelsCacheChanged() - { - if (this->ui->tvp_OwnAircraftModels->displayAutomatically()) - { - this->ui->tvp_OwnAircraftModels->updateContainer(this->m_cachedOwnModels.get()); - } - } - CAircraftModel CDbMappingComponent::getEditorAircraftModel() const { CAircraftModel model(ui->editor_Model->getValue()); diff --git a/src/blackgui/components/dbmappingcomponent.h b/src/blackgui/components/dbmappingcomponent.h index 0e8575494..e839dc1ff 100644 --- a/src/blackgui/components/dbmappingcomponent.h +++ b/src/blackgui/components/dbmappingcomponent.h @@ -181,9 +181,6 @@ namespace BlackGui //! Model loading finished void ps_onOwnModelsLoadingFinished(bool success); - //! Own models cache changed - void ps_ownModelsCacheChanged(); - //! Own model count changed void ps_onOwnModelsCountChanged(int count, bool withFilter); @@ -221,7 +218,6 @@ namespace BlackGui BlackMisc::Simulation::FsCommon::CVPilotRulesReader m_vPilotReader; //!< read vPilot rules std::unique_ptr m_modelLoader; //!< read own aircraft models BlackMisc::CData m_cachedVPilotModels { this, &CDbMappingComponent::ps_onVPilotCacheChanged }; //!< cache for latest vPilot rules - BlackMisc::CData m_cachedOwnModels { this, &CDbMappingComponent::ps_ownModelsCacheChanged }; //!< cache for own installed models BlackMisc::CData m_swiftDbUser {this, &CDbMappingComponent::ps_userChanged}; bool m_vPilot1stInit = true; bool m_withVPilot = false; diff --git a/src/blackmisc/blackmisc.pro b/src/blackmisc/blackmisc.pro index e1d64aef1..a67e8fd74 100644 --- a/src/blackmisc/blackmisc.pro +++ b/src/blackmisc/blackmisc.pro @@ -39,6 +39,7 @@ HEADERS += *.h \ $$PWD/simulation/fscommon/*.h \ $$PWD/simulation/fsx/*.h \ $$PWD/simulation/xplane/*.h \ + $$PWD/simulation/data/*.h \ $$PWD/weather/*.h SOURCES += *.cpp \ @@ -54,6 +55,7 @@ SOURCES += *.cpp \ $$PWD/simulation/fscommon/*.cpp \ $$PWD/simulation/fsx/*.cpp \ $$PWD/simulation/xplane/*.cpp \ +# $$PWD/simulation/data/*.cpp \ $$PWD/weather/*.cpp win32 { diff --git a/src/blackmisc/simulation/aircraftmodelloader.cpp b/src/blackmisc/simulation/aircraftmodelloader.cpp index b5235cf5a..8cca91375 100644 --- a/src/blackmisc/simulation/aircraftmodelloader.cpp +++ b/src/blackmisc/simulation/aircraftmodelloader.cpp @@ -19,15 +19,67 @@ namespace BlackMisc { namespace Simulation { - IAircraftModelLoader::IAircraftModelLoader(const CSimulatorInfo &info) : - m_simulatorInfo(info) - { } + IAircraftModelLoader::IAircraftModelLoader(const CSimulatorInfo &info, const QString &rootDirectory, const QStringList &excludeDirs) : + m_simulatorInfo(info), m_rootDirectory(rootDirectory), m_excludedDirectories(excludeDirs) + { + connect(this, &IAircraftModelLoader::loadingFinished, this, &IAircraftModelLoader::ps_loadFinished); + } IAircraftModelLoader::~IAircraftModelLoader() { this->gracefulShutdown(); } + bool IAircraftModelLoader::existsDir(const QString &directory) const + { + if (directory.isEmpty()) { return false; } + QDir dir(directory); + //! \todo not available network dir can make this hang here + return dir.exists(); + } + + void IAircraftModelLoader::ps_loadFinished(bool success) + { + Q_UNUSED(success); + this->m_loadingInProgress = false; + } + + bool IAircraftModelLoader::changeRootDirectory(const QString &directory) + { + if (m_rootDirectory == directory) { return false; } + if (directory.isEmpty() || !existsDir(directory)) { return false; } + + m_rootDirectory = directory; + return true; + } + + void IAircraftModelLoader::startLoading(LoadMode mode) + { + if (this->m_loadingInProgress) { return; } + this->m_loadingInProgress = true; + const bool useCachedData = !mode.testFlag(CacheSkipped) && this->hasCachedData(); + if (useCachedData && mode.testFlag(CacheFirst)) + { + emit loadingFinished(true); + return; + } + else if (useCachedData && mode.testFlag(CacheUntilNewer)) + { + if (!this->areModelFilesUpdated()) + { + emit loadingFinished(true); + return; + } + } + if (mode.testFlag(CacheOnly)) + { + // only cache, but we did not find any data + emit loadingFinished(false); + return; + } + this->startLoadingFromDisk(mode); + } + const CSimulatorInfo &IAircraftModelLoader::supportedSimulators() const { return m_simulatorInfo; @@ -45,7 +97,8 @@ namespace BlackMisc void IAircraftModelLoader::cancelLoading() { - m_cancelLoading = true; + this->m_cancelLoading = true; + this->m_loadingInProgress = true; } void IAircraftModelLoader::gracefulShutdown() diff --git a/src/blackmisc/simulation/aircraftmodelloader.h b/src/blackmisc/simulation/aircraftmodelloader.h index 7362a2063..94e81923a 100644 --- a/src/blackmisc/simulation/aircraftmodelloader.h +++ b/src/blackmisc/simulation/aircraftmodelloader.h @@ -15,6 +15,7 @@ #include "blackmisc/blackmiscexport.h" #include "blackmisc/simulation/aircraftmodellist.h" #include "blackmisc/simulation/simulatorinfo.h" +#include "blackmisc/simulation/data/modelcaches.h" #include "blackmisc/pixmap.h" #include #include @@ -33,23 +34,45 @@ namespace BlackMisc public: //! Parser mode - enum LoadMode + enum LoadModeFlag { - ModeBlocking, - ModeBackground + NotSet = 0, + LoadDirectly = 1 << 0, //!< load syncronously (blocking), normally for testing + LoadInBackground = 1 << 1, //!< load in background, asnycronously + CacheUntilNewer = 1 << 2, //!< use cache until newer data re available + CacheFirst = 1 << 3, //!< always use cache (if it has data) + CacheSkipped = 1 << 4, //!< ignore cache + CacheOnly = 1 << 5, //!< force ignoring the cache + Default = LoadInBackground | CacheFirst //!< default mode }; + Q_DECLARE_FLAGS(LoadMode, LoadModeFlag) //! Destructor virtual ~IAircraftModelLoader(); - //! Start the loading process - virtual void startLoading(LoadMode mode = ModeBackground) = 0; + //! Start the loading process from disk + void startLoading(LoadMode mode = Default); + + //! Change the directory + bool changeRootDirectory(const QString &directory); + + //! Current root directory + QString getRootDirectory() const { return this->m_rootDirectory; } //! Loading finished? virtual bool isLoadingFinished() const = 0; - //! The models loaded - virtual BlackMisc::Simulation::CAircraftModelList getAircraftModels() const = 0; + //! The loaded models + virtual const BlackMisc::Simulation::CAircraftModelList &getAircraftModels() const = 0; + + //! Cache timestamp + virtual QDateTime getCacheTimestamp() const = 0; + + //! Model files updated? + virtual bool areModelFilesUpdated() const = 0; + + //! Any cached data + virtual bool hasCachedData() const = 0; //! A representive pixmap for given model virtual BlackMisc::CPixmap iconForModel(const QString &modelName, BlackMisc::CStatusMessage &statusMessage) const = 0; @@ -78,13 +101,30 @@ namespace BlackMisc protected: //! Constructor - IAircraftModelLoader(const CSimulatorInfo &info = CSimulatorInfo()); + IAircraftModelLoader(const CSimulatorInfo &info, const QString &rootDirectory, const QStringList &excludeDirs = {}); + + //! Check if directory exists + bool existsDir(const QString &directory) const; + + //! Start the loading process from disk + virtual void startLoadingFromDisk(LoadMode mode) = 0; BlackMisc::Simulation::CSimulatorInfo m_simulatorInfo; //!< Corresponding simulator - std::atomic m_cancelLoading { false }; //!< flag + std::atomic m_cancelLoading { false }; //!< flag + std::atomic m_loadingInProgress { false }; //!< Loading in progress + QString m_rootDirectory; //!< root directory parsing aircraft.cfg files + QStringList m_excludedDirectories; //!< directories not to be parsed + + protected slots: + //! Loading finished + void ps_loadFinished(bool success); }; } // namespace } // namespace +Q_DECLARE_METATYPE(BlackMisc::Simulation::IAircraftModelLoader::LoadMode) +Q_DECLARE_METATYPE(BlackMisc::Simulation::IAircraftModelLoader::LoadModeFlag) +Q_DECLARE_OPERATORS_FOR_FLAGS(BlackMisc::Simulation::IAircraftModelLoader::LoadMode) + #endif // guard diff --git a/src/blackmisc/simulation/data/modelcaches.h b/src/blackmisc/simulation/data/modelcaches.h new file mode 100644 index 000000000..0c9c1d73e --- /dev/null +++ b/src/blackmisc/simulation/data/modelcaches.h @@ -0,0 +1,67 @@ +/* Copyright (C) 2016 + * swift project community / contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKMISC_SIMULATION_DATA_MODELCACHES +#define BLACKMISC_SIMULATION_DATA_MODELCACHES + +#include "blackmisc/datacache.h" +#include "blackmisc/simulation/aircraftmodellist.h" + +namespace BlackMisc +{ + namespace Simulation + { + namespace Data + { + //! Trait for model cache + struct ModelCache : public BlackMisc::CDataTrait + { + //! Default value + static const BlackMisc::Simulation::CAircraftModelList &defaultValue() + { + static const BlackMisc::Simulation::CAircraftModelList ml; + return ml; + } + }; + + //! Trait for XP model cache + struct ModelCacheXP : public ModelCache + { + //! Key in data cache + static const char *key() { return "modelcachexp"; } + }; + + //! Trait for FSX model cache + struct ModelCacheFsx : public ModelCache + { + //! Key in data cache + static const char *key() { return "modelcachefsx"; } + }; + + //! Trait for FS9 model cache + struct ModelCacheFs9 : public ModelCache + { + //! Key in data cache + static const char *key() { return "modelcachefs9"; } + }; + + //! Trait for P3D model cache + struct ModelCacheP3D : public ModelCache + { + //! Key in data cache + static const char *key() { return "modelcachep3d"; } + }; + + } // ns + } // ns +} // ns + +#endif // guard diff --git a/src/blackmisc/simulation/fscommon/aircraftcfgparser.cpp b/src/blackmisc/simulation/fscommon/aircraftcfgparser.cpp index e9cd16b8b..4b1bc824c 100644 --- a/src/blackmisc/simulation/fscommon/aircraftcfgparser.cpp +++ b/src/blackmisc/simulation/fscommon/aircraftcfgparser.cpp @@ -9,6 +9,7 @@ #include "aircraftcfgparser.h" #include "blackmisc/simulation/fscommon/fscommonutil.h" +#include "blackmisc/fileutils.h" #include "blackmisc/predicates.h" #include "blackmisc/logmessage.h" @@ -23,12 +24,8 @@ namespace BlackMisc { namespace FsCommon { - CAircraftCfgParser::CAircraftCfgParser() { } - - CAircraftCfgParser::CAircraftCfgParser(const CSimulatorInfo &simInfo, const QString &rootDirectory, const QStringList &exludes) : - IAircraftModelLoader(simInfo), - m_rootDirectory(rootDirectory), - m_excludedDirectories(exludes) + CAircraftCfgParser::CAircraftCfgParser(const CSimulatorInfo &simInfo, const QString &rootDirectory, const QStringList &excludeDirs) : + IAircraftModelLoader(simInfo, rootDirectory, excludeDirs) { } std::unique_ptr CAircraftCfgParser::createModelLoader(const CSimulatorInfo &simInfo) @@ -64,15 +61,6 @@ namespace BlackMisc if (this->m_parserWorker) { this->m_parserWorker->waitForFinished(); } } - bool CAircraftCfgParser::changeRootDirectory(const QString &directory) - { - if (m_rootDirectory == directory) { return false; } - if (directory.isEmpty() || !existsDir(directory)) { return false; } - - m_rootDirectory = directory; - return true; - } - CPixmap CAircraftCfgParser::iconForModel(const QString &modelString, CStatusMessage &statusMessage) const { static const CPixmap empty {}; @@ -101,13 +89,13 @@ namespace BlackMisc return empty; } - void CAircraftCfgParser::startLoading(LoadMode mode) + void CAircraftCfgParser::startLoadingFromDisk(LoadMode mode) { - if (mode == ModeBackground) + if (mode.testFlag(LoadInBackground)) { if (m_parserWorker && !m_parserWorker->isFinished()) { return; } - auto rootDirectory = m_rootDirectory; - auto excludedDirectories = m_excludedDirectories; + const QString rootDirectory(m_rootDirectory); // copy + const QStringList excludedDirectories(m_excludedDirectories); // copy m_parserWorker = BlackMisc::CWorker::fromTask(this, "CAircraftCfgParser::changeDirectory", [this, rootDirectory, excludedDirectories]() { @@ -117,13 +105,18 @@ namespace BlackMisc }); m_parserWorker->thenWithResult>(this, [this](const auto &pair) { - if (pair.second) { this->updateCfgEntriesList(pair.first); } + if (pair.second) + { + this->updateCfgEntriesList(pair.first); + this->setModelsInCache(pair.first.toAircraftModelList()); + } }); } - else if (mode == ModeBlocking) + else if (mode == LoadDirectly) { bool ok; - m_parsedCfgEntriesList = performParsing(m_rootDirectory, m_excludedDirectories, &ok); + this->m_parsedCfgEntriesList = performParsing(m_rootDirectory, m_excludedDirectories, &ok); + this->setModelsInCache(this->m_parsedCfgEntriesList.toAircraftModelList()); emit loadingFinished(ok); } } @@ -133,11 +126,68 @@ namespace BlackMisc return !m_parserWorker || m_parserWorker->isFinished(); } - CAircraftModelList CAircraftCfgParser::getAircraftModels() const + QDateTime CAircraftCfgParser::getCacheTimestamp() const { - return getAircraftCfgEntriesList().toAircraftModelList(this->m_simulatorInfo); + if (this->m_simulatorInfo.fsx()) + { + return m_modelCacheFsx.getTimestamp(); + } + else if (this->m_simulatorInfo.fs9()) + { + return m_modelCacheFs9.getTimestamp(); + } + else if (this->m_simulatorInfo.p3d()) + { + return m_modelCacheP3D.getTimestamp(); + } + Q_ASSERT_X(false, Q_FUNC_INFO, "Illegal simulator info"); + return QDateTime(); } + bool CAircraftCfgParser::areModelFilesUpdated() const + { + const QDateTime cacheTs(getCacheTimestamp()); + if (!cacheTs.isValid()) { return true; } + //! \todo KB we cannot use the exclude dirs, a minor disadvantege. Also wonder if it was better to parse a QStringList ofr wildcard + return CFileUtils::containsFileNewerThan(cacheTs, this->getRootDirectory(), true, "*.cfg"); + } + + bool CAircraftCfgParser::hasCachedData() const + { + if (this->m_simulatorInfo.fsx()) + { + return !m_modelCacheFsx.get().isEmpty(); + } + else if (this->m_simulatorInfo.fs9()) + { + return !m_modelCacheFs9.get().isEmpty(); + } + else if (this->m_simulatorInfo.p3d()) + { + return !m_modelCacheP3D.get().isEmpty(); + } + Q_ASSERT_X(false, Q_FUNC_INFO, "Illegal simulator info"); + return false; + } + + const CAircraftModelList &CAircraftCfgParser::getAircraftModels() const + { + static const CAircraftModelList empty; + if (this->m_simulatorInfo.fsx()) + { + return m_modelCacheFsx.get(); + } + else if (this->m_simulatorInfo.fs9()) + { + return m_modelCacheFs9.get(); + } + else if (this->m_simulatorInfo.p3d()) + { + return m_modelCacheP3D.get(); + } + Q_ASSERT_X(false, Q_FUNC_INFO, "Illegal simulator info"); + return empty; + } void CAircraftCfgParser::updateCfgEntriesList(const CAircraftCfgEntriesList &cfgEntriesList) { @@ -145,6 +195,24 @@ namespace BlackMisc emit loadingFinished(true); } + CStatusMessage CAircraftCfgParser::setModelsInCache(const CAircraftModelList &models) + { + if (this->m_simulatorInfo.fsx()) + { + return m_modelCacheFsx.set(models); + } + else if (this->m_simulatorInfo.fs9()) + { + return m_modelCacheFs9.set(models); + } + else if (this->m_simulatorInfo.p3d()) + { + return m_modelCacheP3D.set(models); + } + Q_ASSERT_X(false, Q_FUNC_INFO, "Illegal simulator info"); + return CStatusMessage(this, CStatusMessage::SeverityError, "Wrong simulator type"); + } + CAircraftCfgEntriesList CAircraftCfgParser::performParsing(const QString &directory, const QStringList &excludeDirectories, bool *ok) { // @@ -205,7 +273,7 @@ namespace BlackMisc // remark: in a 1st version I have used QSettings to parse to file as ini file // unfortunately some files are malformed which could end up in wrong data - QString fileName = file.absoluteFilePath(); + const QString fileName = file.absoluteFilePath(); QFile file(fileName); if (!file.open(QFile::ReadOnly | QFile::Text)) { @@ -335,14 +403,6 @@ namespace BlackMisc return result; } - bool CAircraftCfgParser::existsDir(const QString &directory) const - { - if (directory.isEmpty()) { return false; } - QDir dir(directory); - //! \todo not available network dir can make this hang here - return dir.exists(); - } - QString CAircraftCfgParser::fixedStringContent(const QSettings &settings, const QString &key) { return fixedStringContent(settings.value(key)); diff --git a/src/blackmisc/simulation/fscommon/aircraftcfgparser.h b/src/blackmisc/simulation/fscommon/aircraftcfgparser.h index 31f07977b..5a41fed7f 100644 --- a/src/blackmisc/simulation/fscommon/aircraftcfgparser.h +++ b/src/blackmisc/simulation/fscommon/aircraftcfgparser.h @@ -15,8 +15,10 @@ #include "blackmisc/blackmiscexport.h" #include "blackmisc/worker.h" #include "blackmisc/pixmap.h" +#include "blackmisc/datacache.h" #include "blackmisc/simulation/aircraftmodelloader.h" #include "blackmisc/simulation/fscommon/aircraftcfgentrieslist.h" +#include "blackmisc/simulation/data/modelcaches.h" #include @@ -32,35 +34,24 @@ namespace BlackMisc Q_OBJECT public: - //! Destructor - CAircraftCfgParser(); - //! Constructor CAircraftCfgParser(const BlackMisc::Simulation::CSimulatorInfo &simInfo, const QString &rootDirectory, const QStringList &exludes = {}); //! Virtual destructor virtual ~CAircraftCfgParser(); - //! Change the directory - bool changeRootDirectory(const QString &directory); - - //! Current root directory - QString getRootDirectory() const { return this->m_rootDirectory; } - //! Get parsed aircraft cfg entries list const CAircraftCfgEntriesList &getAircraftCfgEntriesList() const { return m_parsedCfgEntriesList; } - //! \copydoc IAircraftModelLoader::iconForModel + //! \name Interface functions + //! @{ virtual BlackMisc::CPixmap iconForModel(const QString &modelName, BlackMisc::CStatusMessage &statusMessage) const override; - - //! \copydoc IAircraftModelLoader::startLoading - virtual void startLoading(LoadMode mode = ModeBackground) override; - - //! \copydoc IAircraftModelLoader::isLoadingFinished virtual bool isLoadingFinished() const override; - - //! \copydoc IAircraftModelLoader::getAircraftModels - virtual BlackMisc::Simulation::CAircraftModelList getAircraftModels() const override; + virtual bool areModelFilesUpdated() const override; + virtual bool hasCachedData() const override; + virtual QDateTime getCacheTimestamp() const override; + virtual const BlackMisc::Simulation::CAircraftModelList &getAircraftModels() const override; + //! @} //! Create an parser object for given simulator static std::unique_ptr createModelLoader(const BlackMisc::Simulation::CSimulatorInfo &simInfo); @@ -69,6 +60,15 @@ namespace BlackMisc //! Parsed or injected entires void updateCfgEntriesList(const BlackMisc::Simulation::FsCommon::CAircraftCfgEntriesList &cfgEntriesList); + protected: + //! Set cached values + BlackMisc::CStatusMessage setModelsInCache(const BlackMisc::Simulation::CAircraftModelList &models); + + //! \name Interface functions + //! @{ + virtual void startLoadingFromDisk(LoadMode mode) override; + //! @} + private: //! Section within file enum FileSection @@ -78,9 +78,6 @@ namespace BlackMisc Unknown }; - //! Does the directory exist? - bool existsDir(const QString &directory = "") const; - //! Perform the parsing //! \threadsafe CAircraftCfgEntriesList performParsing(const QString &directory, const QStringList &excludeDirectories, bool *ok); @@ -94,10 +91,13 @@ namespace BlackMisc //! Content after "=" static QString getFixedIniLineContent(const QString &line); - QString m_rootDirectory; //!< root directory parsing aircraft.cfg files - QStringList m_excludedDirectories; //!< directories not to be parsed CAircraftCfgEntriesList m_parsedCfgEntriesList; //!< parsed entries QPointer m_parserWorker; //!< worker will destroy itself, so weak pointer + + //! \todo KB/MS Is there nothing better than having 3 cache members + BlackMisc::CData m_modelCacheFsx {this}; //!< FSX cache + BlackMisc::CData m_modelCacheFs9 {this}; //!< Fs9 cache + BlackMisc::CData m_modelCacheP3D {this}; //!< P3D cache }; } // namespace } // namespace diff --git a/src/blackmisc/simulation/xplane/aircraftmodelloaderxplane.cpp b/src/blackmisc/simulation/xplane/aircraftmodelloaderxplane.cpp index 3bda32904..d02671b1d 100644 --- a/src/blackmisc/simulation/xplane/aircraftmodelloaderxplane.cpp +++ b/src/blackmisc/simulation/xplane/aircraftmodelloaderxplane.cpp @@ -11,6 +11,7 @@ #include "xplaneutil.h" #include "blackmisc/predicates.h" #include "blackmisc/logmessage.h" +#include "blackmisc/fileutils.h" #include #include @@ -43,13 +44,8 @@ namespace BlackMisc } } - CAircraftModelLoaderXPlane::CAircraftModelLoaderXPlane() - { } - - CAircraftModelLoaderXPlane::CAircraftModelLoaderXPlane(const CSimulatorInfo &simInfo, const QString &rootDirectory, const QStringList &exludes) : - IAircraftModelLoader(simInfo), - m_rootDirectory(rootDirectory), - m_excludedDirectories(exludes) + CAircraftModelLoaderXPlane::CAircraftModelLoaderXPlane(const CSimulatorInfo &simInfo, const QString &rootDirectory, const QStringList &excludeDirs) : + IAircraftModelLoader(simInfo, rootDirectory, excludeDirs) { } CAircraftModelLoaderXPlane::~CAircraftModelLoaderXPlane() @@ -58,15 +54,6 @@ namespace BlackMisc if (this->m_parserWorker) { this->m_parserWorker->waitForFinished(); } } - bool CAircraftModelLoaderXPlane::changeRootDirectory(const QString &directory) - { - if (m_rootDirectory == directory) { return false; } - if (directory.isEmpty() || !existsDir(directory)) { return false; } - - m_rootDirectory = directory; - return true; - } - CPixmap CAircraftModelLoaderXPlane::iconForModel(const QString &modelString, CStatusMessage &statusMessage) const { // X-Plane does not have previews. Maybe we can just use the textures? @@ -75,7 +62,7 @@ namespace BlackMisc return {}; } - void CAircraftModelLoaderXPlane::startLoading(LoadMode mode) + void CAircraftModelLoaderXPlane::startLoadingFromDisk(LoadMode mode) { m_installedModels.clear(); if (m_rootDirectory.isEmpty()) @@ -84,7 +71,7 @@ namespace BlackMisc return; } - if (mode == ModeBackground) + if (mode.testFlag(LoadInBackground)) { if (m_parserWorker && !m_parserWorker->isFinished()) { return; } auto rootDirectory = m_rootDirectory; @@ -100,7 +87,7 @@ namespace BlackMisc this->updateInstalledModels(models); }); } - else if (mode == ModeBlocking) + else if (mode.testFlag(LoadDirectly)) { m_installedModels = performParsing(m_rootDirectory, m_excludedDirectories); emit loadingFinished(true); @@ -112,7 +99,27 @@ namespace BlackMisc return !m_parserWorker || m_parserWorker->isFinished(); } - CAircraftModelList CAircraftModelLoaderXPlane::getAircraftModels() const + bool CAircraftModelLoaderXPlane::areModelFilesUpdated() const + { + const QDateTime cacheTs(getCacheTimestamp()); + if (!cacheTs.isValid()) { return true; } + //! \todo KB we cannot use the exclude dirs, a minor disadvantege. Also wonder if it was better to parse a QStringList ofr wildcard + return CFileUtils::containsFileNewerThan(cacheTs, this->getRootDirectory(), true, "xsb_aircraft.txt"); + } + + bool CAircraftModelLoaderXPlane::hasCachedData() const + { + //! \todo KB + return false; + } + + QDateTime CAircraftModelLoaderXPlane::getCacheTimestamp() const + { + //! \todo KB add cache and report back + return QDateTime(); + } + + const CAircraftModelList &CAircraftModelLoaderXPlane::getAircraftModels() const { return m_installedModels; } @@ -146,7 +153,7 @@ namespace BlackMisc { if (models.containsModelString(model.getModelString())) { - CLogMessage(static_cast(nullptr)).warning("Model %1 exists already! Potential model string conflict! Ignoring it.") << model.getModelString(); + CLogMessage(static_cast(nullptr)).warning("Model %1 exists already! Potential model string conflict! Ignoring it.") << model.getModelString(); } models.push_back(model); } @@ -216,7 +223,6 @@ namespace BlackMisc m_cslPackages.clear(); - QDir searchPath(rootDirectory, "xsb_aircraft.txt"); QDirIterator it(searchPath, QDirIterator::Subdirectories); while (it.hasNext()) @@ -282,14 +288,6 @@ namespace BlackMisc return installedModels; } - bool CAircraftModelLoaderXPlane::existsDir(const QString &directory) const - { - if (directory.isEmpty()) { return false; } - QDir dir(directory); - //! \todo not available network dir can make this hang here - return dir.exists(); - } - bool CAircraftModelLoaderXPlane::doPackageSub(QString &ioPath) { for (auto i = m_cslPackages.begin(); i != m_cslPackages.end(); ++i) @@ -353,7 +351,7 @@ namespace BlackMisc { line = stream.readLine(); } - while(line.isEmpty() && !stream.atEnd()); + while (line.isEmpty() && !stream.atEnd()); return line; } @@ -376,7 +374,7 @@ namespace BlackMisc // Get obj header QFile objFile(fullPath); - if(!objFile.open(QIODevice::ReadOnly | QIODevice::Text)) + if (!objFile.open(QIODevice::ReadOnly | QIODevice::Text)) { CLogMessage(this).warning("Object %1 does not exist.") << fullPath; return false; diff --git a/src/blackmisc/simulation/xplane/aircraftmodelloaderxplane.h b/src/blackmisc/simulation/xplane/aircraftmodelloaderxplane.h index 192bb18b4..42127f4e9 100644 --- a/src/blackmisc/simulation/xplane/aircraftmodelloaderxplane.h +++ b/src/blackmisc/simulation/xplane/aircraftmodelloaderxplane.h @@ -35,37 +35,32 @@ namespace BlackMisc Q_OBJECT public: - //! Constructor - CAircraftModelLoaderXPlane(); - //! Constructor CAircraftModelLoaderXPlane(const BlackMisc::Simulation::CSimulatorInfo &simInfo, const QString &rootDirectory, const QStringList &exludes = {}); //! Virtual destructor virtual ~CAircraftModelLoaderXPlane(); - //! Change the directory - bool changeRootDirectory(const QString &directory); - - //! Current root directory - QString getRootDirectory() const { return this->m_rootDirectory; } - - //! \copydoc IAircraftModelLoader::iconForModel + //! \name Interface functions + //! @{ virtual BlackMisc::CPixmap iconForModel(const QString &modelName, BlackMisc::CStatusMessage &statusMessage) const override; - - //! \copydoc IAircraftModelLoader::startLoading - virtual void startLoading(LoadMode mode = ModeBackground) override; - - //! \copydoc IAircraftModelLoader::isLoadingFinished virtual bool isLoadingFinished() const override; - - //! \copydoc IAircraftModelLoader::getAircraftModels - virtual BlackMisc::Simulation::CAircraftModelList getAircraftModels() const override; + virtual bool areModelFilesUpdated() const override; + virtual bool hasCachedData() const override; + virtual QDateTime getCacheTimestamp() const override; + virtual const BlackMisc::Simulation::CAircraftModelList &getAircraftModels() const override; + //! @} public slots: //! Parsed or injected models void updateInstalledModels(const BlackMisc::Simulation::CAircraftModelList &models); + protected: + //! \name Interface functions + //! @{ + virtual void startLoadingFromDisk(LoadMode mode) override; + //! @} + private: struct CSLPlane { @@ -98,8 +93,6 @@ namespace BlackMisc BlackMisc::Simulation::CAircraftModelList parseFlyableAirplanes(const QString &rootDirectory, const QStringList &excludeDirectories); BlackMisc::Simulation::CAircraftModelList parseCslPackages(const QString &rootDirectory, const QStringList &excludeDirectories); - //! Does the directory exist? - bool existsDir(const QString &directory = QString()) const; bool doPackageSub(QString &ioPath); bool parseExportCommand(const QStringList &tokens, CSLPackage &package, const QString &path, int lineNum); @@ -118,8 +111,6 @@ namespace BlackMisc CSLPackage parsePackageHeader(const QString &path, const QString &content); void parseFullPackage(const QString &content, CSLPackage &package); - QString m_rootDirectory; //!< root directory parsing aircraft.cfg files - QStringList m_excludedDirectories; //!< directories not to be parsed QPointer m_parserWorker; //!< worker will destroy itself, so weak pointer QVector m_cslPackages; //!< Parsed Packages. No lock required since accessed only from one thread BlackMisc::Simulation::CAircraftModelList m_installedModels; diff --git a/src/plugins/simulator/fscommon/simulatorfscommon.cpp b/src/plugins/simulator/fscommon/simulatorfscommon.cpp index 5fe032ae0..6050e5500 100644 --- a/src/plugins/simulator/fscommon/simulatorfscommon.cpp +++ b/src/plugins/simulator/fscommon/simulatorfscommon.cpp @@ -52,7 +52,7 @@ namespace BlackSimPlugin } else { - m_aircraftCfgParser->startLoading(CAircraftCfgParser::ModeBackground); + m_aircraftCfgParser->startLoading(CAircraftCfgParser::LoadInBackground); } // // reading from cache / settings would go here