From 8dba22f7f0abf76f7168aaaeeb03f27e14923405 Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Wed, 23 Sep 2015 18:10:41 +0200 Subject: [PATCH] refs #452, updated vPilot reader/sets * Using ITimestampBased * removed mapping / unsing CAircraftModel * graceful shutdown in reader --- .../simulation/fscommon/vpilotmodelrule.cpp | 41 +++++- .../simulation/fscommon/vpilotmodelrule.h | 28 ++--- .../fscommon/vpilotmodelruleset.cpp | 38 ++++-- .../simulation/fscommon/vpilotmodelruleset.h | 6 +- .../simulation/fscommon/vpilotrulesreader.cpp | 119 ++++++++++++++++-- .../simulation/fscommon/vpilotrulesreader.h | 57 +++++++-- 6 files changed, 228 insertions(+), 61 deletions(-) diff --git a/src/blackmisc/simulation/fscommon/vpilotmodelrule.cpp b/src/blackmisc/simulation/fscommon/vpilotmodelrule.cpp index 72aeeb7aa..81bc71ad5 100644 --- a/src/blackmisc/simulation/fscommon/vpilotmodelrule.cpp +++ b/src/blackmisc/simulation/fscommon/vpilotmodelrule.cpp @@ -8,8 +8,14 @@ */ #include "vpilotmodelrule.h" +#include "blackmisc/aviation/aircrafticaocode.h" +#include "blackmisc/aviation/airlineicaocode.h" +#include "blackmisc/aviation/livery.h" +#include "blackmisc/simulation/distributor.h" using namespace BlackMisc::Network; +using namespace BlackMisc::Aviation; +using namespace BlackMisc::Simulation; namespace BlackMisc { @@ -20,6 +26,7 @@ namespace BlackMisc CVPilotModelRule::CVPilotModelRule() { } CVPilotModelRule::CVPilotModelRule(const QString &modelName, const QString &folder, const QString &typeCode, const QString &callsignPrefix, qint64 updated) : + ITimestampBased(updated), m_modelName(modelName.trimmed().toUpper()), m_folder(folder.trimmed().toUpper()), m_typeCode(typeCode.trimmed().toUpper()), m_callsignPrefix(callsignPrefix.trimmed().toUpper()), m_updatedMsSinceEpoch(updated) { } @@ -44,6 +51,7 @@ namespace BlackMisc CVariant CVPilotModelRule::propertyByIndex(const CPropertyIndex &index) const { if (index.isMyself()) { return CVariant::from(*this); } + if (ITimestampBased::canHandleIndex(index)) { return ITimestampBased::propertyByIndex(index); } ColumnIndex i = index.frontCasted(); switch (i) { @@ -51,8 +59,6 @@ namespace BlackMisc case IndexFolder: return CVariant::from(this->m_folder); case IndexTypeCode: return CVariant::from(this->m_typeCode); case IndexCallsignPrefix: return CVariant::from(this->m_callsignPrefix); - case IndexUpdatedTimestamp: return CVariant::from(this->getUpdateTimestamp()); - case IndexUpdatedMsSinceEpoch: return CVariant::from(this->m_updatedMsSinceEpoch); default: return CValueObject::propertyByIndex(index); } @@ -61,6 +67,7 @@ namespace BlackMisc void CVPilotModelRule::setPropertyByIndex(const CVariant &variant, const CPropertyIndex &index) { if (index.isMyself()) { (*this) = variant.to(); return; } + if (ITimestampBased::canHandleIndex(index)) { ITimestampBased::setPropertyByIndex(variant, index); return; } ColumnIndex i = index.frontCasted(); switch (i) { @@ -68,8 +75,6 @@ namespace BlackMisc case IndexFolder: this->setFolder(variant.value()); break; case IndexTypeCode: this->setTypeCode(variant.value()); break; case IndexCallsignPrefix: this->setCallsignPrefix(variant.value()); break; - case IndexUpdatedTimestamp: this->setUpdateTimestamp(variant.value()); break; - case IndexUpdatedMsSinceEpoch: this->setUpdateTimestamp(variant.value()); break; default: CValueObject::setPropertyByIndex(variant, index); break; @@ -83,10 +88,34 @@ namespace BlackMisc return s; } - CAircraftMapping CVPilotModelRule::toMapping() const + CAircraftModel CVPilotModelRule::toAircraftModel() const { - return CAircraftMapping("vpilot", this->getDistributor(), this->getTypeCode(), this->getCallsignPrefix(), this->getModelName()); + QString al(m_callsignPrefix); + if (al.length() > 3) + { + // some known hardcoded fixes + if (al.startsWith("USAF")) { al = "AIO"; } + } + QString liveryPseudoCode( + al.length() != 3 ? + "" : + al + "." + CLivery::standardLiveryMarker()); + CAircraftIcaoCode aircraftIcao(m_typeCode); + CAirlineIcaoCode airlineIcao(al); + CLivery livery(liveryPseudoCode, airlineIcao, "vPilot rule based"); + CDistributor distributor(getDistributor(), "vPilot based", "", ""); + CAircraftModel model( + this->m_modelName, CAircraftModel::TypeVPilotRuleBased, + "vPilot auto generated", + aircraftIcao, livery + ); + CSimulatorInfo sim(CSimulatorInfo::FSX_P3D); + model.setMSecsSinceEpoch(m_timestampMSecsSinceEpoch); + model.setDistributor(distributor); + model.setSimulatorInfo(sim); + return model; } + } // namespace } // namespace } // namespace diff --git a/src/blackmisc/simulation/fscommon/vpilotmodelrule.h b/src/blackmisc/simulation/fscommon/vpilotmodelrule.h index 9fcd5f57d..3565c8696 100644 --- a/src/blackmisc/simulation/fscommon/vpilotmodelrule.h +++ b/src/blackmisc/simulation/fscommon/vpilotmodelrule.h @@ -13,9 +13,10 @@ #define BLACKMISC_SIMULATION_FSCOMMON_VPILOTMODELRULE_H #include "blackmisc/blackmiscexport.h" -#include "blackmisc/network/aircraftmapping.h" +#include "blackmisc/simulation/aircraftmodel.h" #include "blackmisc/valueobject.h" #include "blackmisc/datastore.h" +#include "blackmisc/timestampbased.h" #include namespace BlackMisc @@ -26,7 +27,8 @@ namespace BlackMisc { //! Value object encapsulating information of software distributor. class BLACKMISC_EXPORT CVPilotModelRule : - public BlackMisc::CValueObject + public BlackMisc::CValueObject, + public ITimestampBased { public: //! Property indexes @@ -35,9 +37,7 @@ namespace BlackMisc IndexModelName = CPropertyIndex::GlobalIndexVPilotModelRule, IndexFolder, IndexTypeCode, - IndexCallsignPrefix, - IndexUpdatedTimestamp, - IndexUpdatedMsSinceEpoch + IndexCallsignPrefix }; //! Default constructor @@ -52,7 +52,7 @@ namespace BlackMisc //! Get folder const QString &getFolder() const { return this->m_folder;} - //! Distributor derived from folder + //! Distributor derived from folder (hardcoded) const QString getDistributor() const; //! Get type code @@ -61,12 +61,6 @@ namespace BlackMisc //! Get callsign prefix const QString &getCallsignPrefix() const { return this->m_callsignPrefix;} - //! Update timestamp - QDateTime getUpdateTimestamp() const { return QDateTime::fromMSecsSinceEpoch(this->m_updatedMsSinceEpoch); } - - //! Updated when - qint64 getUpdateMsSinceEpoch() const { return m_updatedMsSinceEpoch; } - //! Model name void setModelName(const QString &name) { this->m_modelName = name.trimmed().toUpper(); } @@ -79,12 +73,6 @@ namespace BlackMisc //! Callsign prefix void setCallsignPrefix(const QString &callsign) { this->m_callsignPrefix = callsign.trimmed().toUpper(); } - //! Set update timestamp - void setUpdateTimestamp(qint64 timestamp) { this->m_updatedMsSinceEpoch = timestamp; } - - //! Set update timestamp - void setUpdateTimestamp(const QDateTime ×tamp) { this->m_updatedMsSinceEpoch = timestamp.toMSecsSinceEpoch(); } - //! \copydoc CValueObject::propertyByIndex CVariant propertyByIndex(const BlackMisc::CPropertyIndex &index) const; @@ -94,8 +82,8 @@ namespace BlackMisc //! \copydoc CValueObject::convertToQString QString convertToQString(bool i18n = false) const; - //! Convert to mapping - BlackMisc::Network::CAircraftMapping toMapping() const; + //! Convert into aircraft model + CAircraftModel toAircraftModel() const; private: BLACK_ENABLE_TUPLE_CONVERSION(CVPilotModelRule) diff --git a/src/blackmisc/simulation/fscommon/vpilotmodelruleset.cpp b/src/blackmisc/simulation/fscommon/vpilotmodelruleset.cpp index 3c8e54fd9..e9bdee094 100644 --- a/src/blackmisc/simulation/fscommon/vpilotmodelruleset.cpp +++ b/src/blackmisc/simulation/fscommon/vpilotmodelruleset.cpp @@ -9,6 +9,7 @@ #include "vpilotmodelruleset.h" #include "blackmisc/predicates.h" +#include using namespace BlackMisc::Network; @@ -42,16 +43,6 @@ namespace BlackMisc }); } - CAircraftMappingList CVPilotModelRuleSet::toMappings() const - { - CAircraftMappingList mappings; - for (const CVPilotModelRule &rule : (*this)) - { - mappings.push_back(rule.toMapping()); - } - return mappings; - } - QStringList CVPilotModelRuleSet::toUpper(const QStringList &stringList) { QStringList upper; @@ -120,6 +111,33 @@ namespace BlackMisc return c; } + CAircraftModelList CVPilotModelRuleSet::toAircraftModels() const + { + QStringList modelNames; + CAircraftModelList models; + for (const CVPilotModelRule &rule : *this) + { + QString m(rule.getModelName()); + if (m.isEmpty()) { continue; } + if (modelNames.contains(m, Qt::CaseInsensitive)) + { + CAircraftModel model(rule.toAircraftModel()); + for (CAircraftModel &exisitingModel : models) + { + if (!exisitingModel.matchesModelString(m, Qt::CaseInsensitive)) { continue; } + exisitingModel.updateMissingParts(model); + break; + } + } + else + { + models.push_back(rule.toAircraftModel()); + modelNames.append(m); + } + } + return models; + } + } // namespace } // namespace } // namespace diff --git a/src/blackmisc/simulation/fscommon/vpilotmodelruleset.h b/src/blackmisc/simulation/fscommon/vpilotmodelruleset.h index b832133aa..551dd297b 100644 --- a/src/blackmisc/simulation/fscommon/vpilotmodelruleset.h +++ b/src/blackmisc/simulation/fscommon/vpilotmodelruleset.h @@ -14,7 +14,7 @@ #include "blackmisc/blackmiscexport.h" #include "blackmisc/simulation/fscommon/vpilotmodelrule.h" -#include "blackmisc/network/aircraftmappinglist.h" +#include "blackmisc/simulation/aircraftmodellist.h" #include "blackmisc/collection.h" #include "blackmisc/sequence.h" @@ -59,8 +59,8 @@ namespace BlackMisc //! Keep given models (if in list) int keepModels(const QStringList &modelsToBeKept); - //! Convert to mappings - BlackMisc::Network::CAircraftMappingList toMappings() const; + //! To aircraft models + BlackMisc::Simulation::CAircraftModelList toAircraftModels() const; private: //! Convert values to upper case diff --git a/src/blackmisc/simulation/fscommon/vpilotrulesreader.cpp b/src/blackmisc/simulation/fscommon/vpilotrulesreader.cpp index 97998f567..497457d23 100644 --- a/src/blackmisc/simulation/fscommon/vpilotrulesreader.cpp +++ b/src/blackmisc/simulation/fscommon/vpilotrulesreader.cpp @@ -8,13 +8,13 @@ */ #include "vpilotrulesreader.h" -#include "blackmisc/network/aircraftmapping.h" #include #include #include #include +using namespace BlackMisc; using namespace BlackMisc::Network; namespace BlackMisc @@ -29,9 +29,21 @@ namespace BlackMisc if (standardDirectory) { this->addDirectory(CVPilotRulesReader::standardMappingsDirectory()); } } + CVPilotRulesReader::~CVPilotRulesReader() + { + gracefulShutdown(); + } + + QStringList CVPilotRulesReader::getFiles() const + { + QReadLocker l(&m_lockData); + return m_fileList; + } + void CVPilotRulesReader::addFilename(const QString &fileName) { - if (this->m_fileList.contains(fileName)) return; + QWriteLocker l(&m_lockData); + if (this->m_fileList.contains(fileName)) { return; } this->m_fileList.append(fileName); } @@ -47,11 +59,53 @@ namespace BlackMisc } } + int CVPilotRulesReader::countFilesLoaded() const + { + QReadLocker l(&m_lockData); + return m_loadedFiles; + } + + CVPilotModelRuleSet CVPilotRulesReader::getRules() const + { + QReadLocker l(&m_lockData); + return m_rules; + } + + int CVPilotRulesReader::getModelsCount() const + { + QReadLocker l(&m_lockData); + return m_models.size(); + } + + CAircraftModelList CVPilotRulesReader::getAsModels() const + { + // already cached? + { + QReadLocker l(&m_lockData); + if (!m_models.isEmpty() || m_rules.isEmpty()) return m_models; + } + + // important: that can take a while and should normally + // run in background + if (m_shutdown) { return CAircraftModelList(); } + CVPilotModelRuleSet rules(getRules()); // thread safe copy + CAircraftModelList models(rules.toAircraftModels()); // long lasting operation + QWriteLocker l(&m_lockData); + m_models = models; + return m_models; + } + int CVPilotRulesReader::countRulesLoaded() const { + QReadLocker l(&m_lockData); return m_rules.size(); } + void CVPilotRulesReader::gracefulShutdown() + { + m_shutdown = true; + } + const QString &CVPilotRulesReader::standardMappingsDirectory() { static QString directory; @@ -64,23 +118,62 @@ namespace BlackMisc return directory; } - bool CVPilotRulesReader::read() + bool CVPilotRulesReader::read(bool convertToModels) { bool success = true; - this->m_loadedFiles = 0; - this->m_fileListWithProblems.clear(); - for (const QString &fn : this->m_fileList) + int loadedFiles = 0; + QStringList filesWithProblems; + CVPilotModelRuleSet rules; + QStringList fileList(getFiles()); + + for (const QString &fn : fileList) { - this->m_loadedFiles++; - bool s = this->loadFile(fn); + if (m_shutdown) { return false; } + loadedFiles++; + bool s = this->loadFile(fn, rules); if (!s) { this->m_fileListWithProblems.append(fn); } success = s && success; } + + { + QWriteLocker l(&m_lockData); + this->m_loadedFiles = loadedFiles; + this->m_fileListWithProblems = filesWithProblems; + this->m_rules = rules; + if (convertToModels) + { + if (m_shutdown) { return false; } + this->m_models = rules.toAircraftModels(); // long lasting operation + } + } + emit readFinished(success); return success; } - bool CVPilotRulesReader::loadFile(const QString &fileName) + CWorker *CVPilotRulesReader::readASync(bool convertToModels) + { + // set a thread safe flag + { + QWriteLocker l(&m_lockData); + if (m_asyncLoadInProgress) { return nullptr; } + m_asyncLoadInProgress = true; + } + BlackMisc::CWorker *worker = BlackMisc::CWorker::fromTask(this, "CVPilotRulesReader", [this, convertToModels]() + { + this->read(convertToModels); + }); + worker->then(this, &CVPilotRulesReader::ps_readASyncFinished); + return worker; + } + + void CVPilotRulesReader::ps_readASyncFinished() + { + QWriteLocker l(&m_lockData); + m_asyncLoadInProgress = false; + } + + bool CVPilotRulesReader::loadFile(const QString &fileName, CVPilotModelRuleSet &ruleSet) { QFile f(fileName); if (!f.exists()) { return false; } @@ -101,8 +194,10 @@ namespace BlackMisc { folder = QFileInfo(fileName).fileName().replace(".vmr", ""); } + + // "2/1/2014 12:00:00 AM", "5/26/2014 2:00:00 PM" QString updated = attributes.namedItem("UpdatedOn").nodeValue(); - QDateTime qt = QDateTime::fromString(updated); + QDateTime qt = QDateTime::fromString(updated, "M/d/yyyy h:mm:ss AP"); qint64 updatedTimestamp = qt.toMSecsSinceEpoch(); int rulesSize = rules.size(); @@ -124,14 +219,14 @@ namespace BlackMisc { if (model.isEmpty()) { continue; } CVPilotModelRule rule(model, folder, typeCode, callsignPrefix, updatedTimestamp); - this->m_rules.push_back(rule); + ruleSet.push_back(rule); } } else { // single model CVPilotModelRule rule(modelName, folder, typeCode, callsignPrefix, updatedTimestamp); - this->m_rules.push_back(rule); + ruleSet.push_back(rule); } } return true; diff --git a/src/blackmisc/simulation/fscommon/vpilotrulesreader.h b/src/blackmisc/simulation/fscommon/vpilotrulesreader.h index 4afef625d..525f66f77 100644 --- a/src/blackmisc/simulation/fscommon/vpilotrulesreader.h +++ b/src/blackmisc/simulation/fscommon/vpilotrulesreader.h @@ -13,9 +13,12 @@ #define BLACKMISC_SIMULATION_FSCOMMON_VPILOTRULESREADER_H #include "blackmisc/blackmiscexport.h" +#include "blackmisc/worker.h" +#include "blackmisc/simulation/aircraftmodellist.h" #include "blackmisc/simulation/fscommon/vpilotmodelruleset.h" #include #include +#include namespace BlackMisc { @@ -33,23 +36,43 @@ namespace BlackMisc CVPilotRulesReader(bool standardDirectory = true, QObject *parent = nullptr); //! Destructor - virtual ~CVPilotRulesReader() {} + virtual ~CVPilotRulesReader(); + + //! Files + //! \threadsafe + QStringList getFiles() const; //! File names + //! \threadsafe void addFilename(const QString &fileName); //! Directory with .vmr files + //! \threadsafe void addDirectory(const QString &directory); //! Loaded files (number) - int countFilesLoaded() const { return m_loadedFiles; } + //! \threadsafe + int countFilesLoaded() const; //! Loaded rules - const CVPilotModelRuleSet &getRules() const { return m_rules; } + //! \threadsafe + CVPilotModelRuleSet getRules() const; + + //! Get as models + //! \threadsafe + BlackMisc::Simulation::CAircraftModelList getAsModels() const; + + //! Get model count + //! \threadsafe + int getModelsCount() const; //! Loaded rules + //! \threadsafe int countRulesLoaded() const; + //! Graceful shutdown + void gracefulShutdown(); + //! The standard directory for vPilot mappings static const QString &standardMappingsDirectory(); @@ -59,18 +82,32 @@ namespace BlackMisc public slots: //! Load data - bool read(); + //! \threadsafe + bool read(bool convertToModels); + + //! Load data in background thread + //! \threadsafe + BlackMisc::CWorker *readASync(bool convertToModels); + + private slots: + //! Asyncronous read finished + void ps_readASyncFinished(); private: - QStringList m_fileList; //!< list of file names - QStringList m_fileListWithProblems; //!< problems during parsing - int m_loadedFiles = 0; //!< loaded files - CVPilotModelRuleSet m_rules; //!< rules list + QStringList m_fileList; //!< list of file names + QStringList m_fileListWithProblems; //!< problems during parsing + int m_loadedFiles = 0; //!< loaded files + CVPilotModelRuleSet m_rules; //!< rules list + bool m_asyncLoadInProgress = false; //!< Asynchronous load in progress + bool m_shutdown = false; //!< Shutdown + mutable BlackMisc::Simulation::CAircraftModelList m_models; //!< converted to models + mutable QReadWriteLock m_lockData; //! Read single file and do parsing - bool loadFile(const QString &fileName); + //! \threadsafe + bool loadFile(const QString &fileName, CVPilotModelRuleSet &ruleSet); - }; + }; } // namespace } // namespace } // namespace