diff --git a/src/blackmisc/simulation/fscommon/modelmappingsprovidervpilot.cpp b/src/blackmisc/simulation/fscommon/modelmappingsprovidervpilot.cpp index 564570913..72f786859 100644 --- a/src/blackmisc/simulation/fscommon/modelmappingsprovidervpilot.cpp +++ b/src/blackmisc/simulation/fscommon/modelmappingsprovidervpilot.cpp @@ -23,111 +23,24 @@ namespace BlackMisc { namespace FsCommon { - CModelMappingsProviderVPilot::CModelMappingsProviderVPilot(bool standardDirectory, QObject *parent) : - IModelMappingsProvider(parent) + IModelMappingsProvider(parent), + m_vPilotReader(new CVPilotRulesReader(standardDirectory, this)) { - if (standardDirectory) { this->addDirectory(CModelMappingsProviderVPilot::standardMappingsDirectory()); } - } - - void CModelMappingsProviderVPilot::addFilename(const QString &fileName) - { - if (this->m_fileList.contains(fileName)) return; - this->m_fileList.append(fileName); - } - - void CModelMappingsProviderVPilot::addDirectory(const QString &directory) - { - QDir dir(directory); - if (!dir.exists()) return; - QStringList nameFilters({"*.vmr"}); - QFileInfoList entries = dir.entryInfoList(nameFilters, QDir::Files | QDir::Readable); - for (const QFileInfo &file : entries) - { - this->addFilename(file.absoluteFilePath()); - } - } - - const QString &CModelMappingsProviderVPilot::standardMappingsDirectory() - { - static QString directory; - if (directory.isEmpty()) - { - directory = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation).first(); - if (!directory.endsWith('/')) directory.append('/'); - directory.append("vPilot Files/Model Matching Rule Sets"); - } - return directory; + // void } bool CModelMappingsProviderVPilot::read() { - bool success = true; - this->m_loadedFiles = 0; - this->m_fileListWithProblems.clear(); - for (const QString &fn : this->m_fileList) + Q_ASSERT_X(this->m_vPilotReader, Q_FUNC_INFO, "missing reader"); + bool success = this->m_vPilotReader->read(); + if (success) { - this->m_loadedFiles++; - bool s = this->loadFile(fn); - if (!s) { this->m_fileListWithProblems.append(fn); } - success = s && success; + this->m_mappings = this->m_vPilotReader->getRules().toMappings(); } return success; } - bool CModelMappingsProviderVPilot::loadFile(const QString &fileName) - { - QFile f(fileName); - if (!f.exists()) { return false; } - if (!f.open(QFile::ReadOnly | QFile::Text)) { return false; } - QByteArray fc = f.readAll(); - if (fc.isEmpty()) { return false; } - QDomDocument doc; - if (!doc.setContent(fc)) { return false; } - QDomNodeList rules = doc.elementsByTagName("ModelMatchRule"); - if (rules.isEmpty()) { return false; } - - QString folder; - QString updated; - QDomNodeList mmRuleSet = doc.elementsByTagName("ModelMatchRuleSet"); - if (mmRuleSet.size() > 0) - { - QDomNamedNodeMap attributes = mmRuleSet.at(0).attributes(); - folder = attributes.namedItem("Folder").nodeValue(); - updated = attributes.namedItem("UpdatedOn").nodeValue(); - } - int rulesSize = rules.size(); - for (int i = 0; i < rulesSize; i++) - { - QDomNamedNodeMap attributes = rules.at(i).attributes(); - const QString typeCode = attributes.namedItem("TypeCode").nodeValue(); - const QString modelName = attributes.namedItem("ModelName").nodeValue(); - // remark, callsign prefix is airline ICAO code - const QString airlineCode = attributes.namedItem("CallsignPrefix").nodeValue(); - if (modelName.isEmpty()) { continue; } - - // split if we have multiple models - if (modelName.contains("//")) - { - // multiple models - const QStringList models = modelName.split("//"); - for (const QString &model : models) - { - if (model.isEmpty()) { continue; } - CAircraftMapping mapping("vpilot", folder, typeCode, airlineCode, model); - this->m_mappings.push_back(mapping); - } - } - else - { - // single model - CAircraftMapping mapping("vpilot", folder, typeCode, airlineCode, modelName); - this->m_mappings.push_back(mapping); - } - } - return true; - } - } // namespace } // namespace } // namespace diff --git a/src/blackmisc/simulation/fscommon/modelmappingsprovidervpilot.h b/src/blackmisc/simulation/fscommon/modelmappingsprovidervpilot.h index 5619921a7..439ed753c 100644 --- a/src/blackmisc/simulation/fscommon/modelmappingsprovidervpilot.h +++ b/src/blackmisc/simulation/fscommon/modelmappingsprovidervpilot.h @@ -14,7 +14,9 @@ #include "blackmisc/blackmiscexport.h" #include "blackmisc/simulation/modelmappingsprovider.h" +#include "blackmisc/simulation/fscommon/vpilotrulesreader.h" #include +#include namespace BlackMisc { @@ -32,29 +34,12 @@ namespace BlackMisc //! Destructor virtual ~CModelMappingsProviderVPilot() {} - //! File names - void addFilename(const QString &fileName); - - //! Directory with .vmr files - void addDirectory(const QString &directory); - - //! Loaded files (number) - int countFilesLoaded() const { return m_loadedFiles; } - - //! The standard directory for vPilot mappings - static const QString &standardMappingsDirectory(); - public slots: //! Load data virtual bool read() override; private: - QStringList m_fileList; //!< list of file names - QStringList m_fileListWithProblems; //!< problems during parsing - int m_loadedFiles = 0; //!< loaded files - - //! Single file read and parsing - bool loadFile(const QString &fileName); + QScopedPointer m_vPilotReader; //!< used vPilot model reader }; } // namespace } // namespace diff --git a/src/blackmisc/simulation/fscommon/vpilotmodelrule.cpp b/src/blackmisc/simulation/fscommon/vpilotmodelrule.cpp new file mode 100644 index 000000000..72aeeb7aa --- /dev/null +++ b/src/blackmisc/simulation/fscommon/vpilotmodelrule.cpp @@ -0,0 +1,92 @@ +/* Copyright (C) 2015 + * 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. + */ + +#include "vpilotmodelrule.h" + +using namespace BlackMisc::Network; + +namespace BlackMisc +{ + namespace Simulation + { + namespace FsCommon + { + CVPilotModelRule::CVPilotModelRule() { } + + CVPilotModelRule::CVPilotModelRule(const QString &modelName, const QString &folder, const QString &typeCode, const QString &callsignPrefix, qint64 updated) : + m_modelName(modelName.trimmed().toUpper()), m_folder(folder.trimmed().toUpper()), + m_typeCode(typeCode.trimmed().toUpper()), m_callsignPrefix(callsignPrefix.trimmed().toUpper()), m_updatedMsSinceEpoch(updated) + { } + + const QString CVPilotModelRule::getDistributor() const + { + QString f(this->getFolder().toUpper().simplified()); + f.replace(" ", ""); + if (f.isEmpty()) return ("UNKNOWN"); + if (f.startsWith("WOAI", Qt::CaseInsensitive)) { return "WOAI"; } + if (f.startsWith("WORLDOFAI", Qt::CaseInsensitive)) { return "WOAI"; } + if (f.startsWith("IVAO", Qt::CaseInsensitive)) { return "IVAO"; } + if (f.startsWith("P3D", Qt::CaseInsensitive)) { return "P3D"; } + if (f.startsWith("FSX", Qt::CaseInsensitive)) { return "FSX"; } + if (f.startsWith("MYTRAFFIC", Qt::CaseInsensitive)) { return "MYTRAFFIC"; } + if (f.startsWith("JUSTFLIGHT", Qt::CaseInsensitive)) { return "JUSTFLIGHT"; } + if (f.startsWith("ULTIMATETRAFFIC", Qt::CaseInsensitive)) { return "ULTIMATETRAFFIC"; } + if (f.startsWith("VIP", Qt::CaseInsensitive)) { return "VIP"; } + return "??? - " + f; + } + + CVariant CVPilotModelRule::propertyByIndex(const CPropertyIndex &index) const + { + if (index.isMyself()) { return CVariant::from(*this); } + ColumnIndex i = index.frontCasted(); + switch (i) + { + case IndexModelName: return CVariant::from(this->m_modelName); + 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); + } + } + + void CVPilotModelRule::setPropertyByIndex(const CVariant &variant, const CPropertyIndex &index) + { + if (index.isMyself()) { (*this) = variant.to(); return; } + ColumnIndex i = index.frontCasted(); + switch (i) + { + case IndexModelName: this->setModelName(variant.value()); break; + 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; + } + } + + QString CVPilotModelRule::convertToQString(bool i18n) const + { + Q_UNUSED(i18n); + QString s(this->m_modelName); + return s; + } + + CAircraftMapping CVPilotModelRule::toMapping() const + { + return CAircraftMapping("vpilot", this->getDistributor(), this->getTypeCode(), this->getCallsignPrefix(), this->getModelName()); + } + } // namespace + } // namespace +} // namespace diff --git a/src/blackmisc/simulation/fscommon/vpilotmodelrule.h b/src/blackmisc/simulation/fscommon/vpilotmodelrule.h new file mode 100644 index 000000000..9fcd5f57d --- /dev/null +++ b/src/blackmisc/simulation/fscommon/vpilotmodelrule.h @@ -0,0 +1,121 @@ +/* Copyright (C) 2015 + * 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_FSCOMMON_VPILOTMODELRULE_H +#define BLACKMISC_SIMULATION_FSCOMMON_VPILOTMODELRULE_H + +#include "blackmisc/blackmiscexport.h" +#include "blackmisc/network/aircraftmapping.h" +#include "blackmisc/valueobject.h" +#include "blackmisc/datastore.h" +#include + +namespace BlackMisc +{ + namespace Simulation + { + namespace FsCommon + { + //! Value object encapsulating information of software distributor. + class BLACKMISC_EXPORT CVPilotModelRule : + public BlackMisc::CValueObject + { + public: + //! Property indexes + enum ColumnIndex + { + IndexModelName = CPropertyIndex::GlobalIndexVPilotModelRule, + IndexFolder, + IndexTypeCode, + IndexCallsignPrefix, + IndexUpdatedTimestamp, + IndexUpdatedMsSinceEpoch + }; + + //! Default constructor + CVPilotModelRule(); + + //! Default constructor. + CVPilotModelRule(const QString &modelName, const QString &folder, const QString &typeCode, const QString &callsignPrefix, qint64 updated); + + //! Get model name + const QString &getModelName() const { return this->m_modelName;} + + //! Get folder + const QString &getFolder() const { return this->m_folder;} + + //! Distributor derived from folder + const QString getDistributor() const; + + //! Get type code + const QString &getTypeCode() const { return this->m_typeCode;} + + //! 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(); } + + //! Type code + void setTypeCode(const QString &code) { this->m_typeCode = code.trimmed().toUpper(); } + + //! Folder + void setFolder(const QString &folder) { this->m_folder = folder.trimmed().toUpper(); } + + //! 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; + + //! \copydoc CValueObject::setPropertyByIndex + void setPropertyByIndex(const CVariant &variant, const BlackMisc::CPropertyIndex &index); + + //! \copydoc CValueObject::convertToQString + QString convertToQString(bool i18n = false) const; + + //! Convert to mapping + BlackMisc::Network::CAircraftMapping toMapping() const; + + private: + BLACK_ENABLE_TUPLE_CONVERSION(CVPilotModelRule) + QString m_modelName; //!< model name + QString m_folder; //!< folder + QString m_typeCode; //!< type code, aka aircraft ICAO + QString m_callsignPrefix; //!< callsign prefix, aka airline ICAO + qint64 m_updatedMsSinceEpoch; //!< updated when + }; + + } // namespace + } // namespace +} // namespace + +Q_DECLARE_METATYPE(BlackMisc::Simulation::FsCommon::CVPilotModelRule) +BLACK_DECLARE_TUPLE_CONVERSION(BlackMisc::Simulation::FsCommon::CVPilotModelRule, ( + attr(o.m_typeCode, flags ()), + attr(o.m_callsignPrefix, flags ()), + attr(o.m_modelName, flags ()), + attr(o.m_folder, flags ()), + attr(o.m_updatedMsSinceEpoch) + )) +#endif // guard diff --git a/src/blackmisc/simulation/fscommon/vpilotmodelruleset.cpp b/src/blackmisc/simulation/fscommon/vpilotmodelruleset.cpp new file mode 100644 index 000000000..3c8e54fd9 --- /dev/null +++ b/src/blackmisc/simulation/fscommon/vpilotmodelruleset.cpp @@ -0,0 +1,125 @@ +/* Copyright (C) 2015 + * 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. + */ + +#include "vpilotmodelruleset.h" +#include "blackmisc/predicates.h" + +using namespace BlackMisc::Network; + +namespace BlackMisc +{ + namespace Simulation + { + namespace FsCommon + { + + CVPilotModelRuleSet::CVPilotModelRuleSet(const CCollection &other) : + CCollection(other) + { } + + CVPilotModelRuleSet CVPilotModelRuleSet::findByModelName(const QString &modelName) const + { + return this->findBy(&CVPilotModelRule::getModelName, modelName.trimmed().toUpper()); + } + + CVPilotModelRule CVPilotModelRuleSet::findFirstByModelName(const QString &modelName) const + { + return this->findFirstByOrDefault(&CVPilotModelRule::getModelName, modelName.trimmed().toUpper()); + } + + CVPilotModelRuleSet CVPilotModelRuleSet::findModelsStartingWith(const QString &modelName) const + { + QString mn(modelName.trimmed().toUpper()); + return this->findBy([ = ](const CVPilotModelRule & rule) + { + return rule.getModelName().startsWith(mn, Qt::CaseInsensitive); + }); + } + + 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; + for (const QString &s : stringList) + { + upper.append(s.toUpper()); + } + return upper; + } + + QStringList CVPilotModelRuleSet::getSortedModelNames() const + { + QStringList ms; + for (const CVPilotModelRule &rule : (*this)) + { + ms.append(rule.getModelName()); + } + ms.sort(Qt::CaseInsensitive); + return ms; + } + + QStringList CVPilotModelRuleSet::getSortedDistributors() const + { + QStringList distributors; + for (const CVPilotModelRule &rule : (*this)) + { + QString d(rule.getDistributor()); + if (distributors.contains(d)) { continue; } + distributors.append(d); + } + distributors.sort(Qt::CaseInsensitive); + return distributors; + } + + int CVPilotModelRuleSet::removeModels(const QStringList &modelsToBeRemoved) + { + QStringList knownModels(getSortedModelNames()); + if (knownModels.isEmpty()) { return 0; } + + QStringList remove(toUpper(modelsToBeRemoved)); + remove.sort(); + + QSet removeSet(knownModels.toSet().intersect(remove.toSet())); + int c = 0; + for (const QString &model : removeSet) + { + c += this->removeIf(&CVPilotModelRule::getModelName, model); + } + return c; + } + + int CVPilotModelRuleSet::keepModels(const QStringList &modelsToBeKept) + { + QStringList knownModels(getSortedModelNames()); + if (knownModels.isEmpty()) { return 0; } + + QStringList keep(toUpper(modelsToBeKept)); + keep.sort(); + + QSet removeSet(knownModels.toSet().subtract(keep.toSet())); + int c = 0; + for (const QString &model : removeSet) + { + c += this->removeIf(&CVPilotModelRule::getModelName, model); + } + return c; + } + + } // namespace + } // namespace +} // namespace diff --git a/src/blackmisc/simulation/fscommon/vpilotmodelruleset.h b/src/blackmisc/simulation/fscommon/vpilotmodelruleset.h new file mode 100644 index 000000000..b832133aa --- /dev/null +++ b/src/blackmisc/simulation/fscommon/vpilotmodelruleset.h @@ -0,0 +1,78 @@ +/* Copyright (C) 2015 + * 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_FSCOMMON_VPILOTMODELRULELIST_H +#define BLACKMISC_SIMULATION_FSCOMMON_VPILOTMODELRULELIST_H + +#include "blackmisc/blackmiscexport.h" +#include "blackmisc/simulation/fscommon/vpilotmodelrule.h" +#include "blackmisc/network/aircraftmappinglist.h" +#include "blackmisc/collection.h" +#include "blackmisc/sequence.h" + +namespace BlackMisc +{ + namespace Simulation + { + namespace FsCommon + { + //! Value object reading a set of vPilot rules + class BLACKMISC_EXPORT CVPilotModelRuleSet : + public CCollection, + public BlackMisc::Mixin::MetaType + { + public: + BLACKMISC_DECLARE_USING_MIXIN_METATYPE(CVPilotModelRuleSet) + + //! Default constructor. + CVPilotModelRuleSet() = default; + + //! Construct from a base class object. + CVPilotModelRuleSet(const CCollection &other); + + //! Find by model string + CVPilotModelRuleSet findByModelName(const QString &modelName) const; + + //! Find first by model string + CVPilotModelRule findFirstByModelName(const QString &modelName) const; + + //! Find models starting with + CVPilotModelRuleSet findModelsStartingWith(const QString &modelName) const; + + //! Model strings + QStringList getSortedModelNames() const; + + //! List of distributors + QStringList getSortedDistributors() const; + + //! Removed given models + int removeModels(const QStringList &modelsToBeRemoved); + + //! Keep given models (if in list) + int keepModels(const QStringList &modelsToBeKept); + + //! Convert to mappings + BlackMisc::Network::CAircraftMappingList toMappings() const; + + private: + //! Convert values to upper case + static QStringList toUpper(const QStringList &stringList); + }; + + } // namespace + } //namespace +} // namespace + +Q_DECLARE_METATYPE(BlackMisc::Simulation::FsCommon::CVPilotModelRuleSet) +Q_DECLARE_METATYPE(BlackMisc::CCollection) +Q_DECLARE_METATYPE(BlackMisc::CSequence) + +#endif //guard diff --git a/src/blackmisc/simulation/fscommon/vpilotrulesreader.cpp b/src/blackmisc/simulation/fscommon/vpilotrulesreader.cpp new file mode 100644 index 000000000..97998f567 --- /dev/null +++ b/src/blackmisc/simulation/fscommon/vpilotrulesreader.cpp @@ -0,0 +1,142 @@ +/* Copyright (C) 2015 + * 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. + */ + +#include "vpilotrulesreader.h" +#include "blackmisc/network/aircraftmapping.h" + +#include +#include +#include +#include + +using namespace BlackMisc::Network; + +namespace BlackMisc +{ + namespace Simulation + { + namespace FsCommon + { + CVPilotRulesReader::CVPilotRulesReader(bool standardDirectory, QObject *parent) : + QObject(parent) + { + if (standardDirectory) { this->addDirectory(CVPilotRulesReader::standardMappingsDirectory()); } + } + + void CVPilotRulesReader::addFilename(const QString &fileName) + { + if (this->m_fileList.contains(fileName)) return; + this->m_fileList.append(fileName); + } + + void CVPilotRulesReader::addDirectory(const QString &directory) + { + QDir dir(directory); + if (!dir.exists()) { return; } + QStringList nameFilters({"*.vmr"}); + QFileInfoList entries = dir.entryInfoList(nameFilters, QDir::Files | QDir::Readable); + for (const QFileInfo &file : entries) + { + this->addFilename(file.absoluteFilePath()); + } + } + + int CVPilotRulesReader::countRulesLoaded() const + { + return m_rules.size(); + } + + const QString &CVPilotRulesReader::standardMappingsDirectory() + { + static QString directory; + if (directory.isEmpty()) + { + directory = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation).first(); + if (!directory.endsWith('/')) { directory.append('/'); } + directory.append("vPilot Files/Model Matching Rule Sets"); + } + return directory; + } + + bool CVPilotRulesReader::read() + { + bool success = true; + this->m_loadedFiles = 0; + this->m_fileListWithProblems.clear(); + for (const QString &fn : this->m_fileList) + { + this->m_loadedFiles++; + bool s = this->loadFile(fn); + if (!s) { this->m_fileListWithProblems.append(fn); } + success = s && success; + } + emit readFinished(success); + return success; + } + + bool CVPilotRulesReader::loadFile(const QString &fileName) + { + QFile f(fileName); + if (!f.exists()) { return false; } + if (!f.open(QFile::ReadOnly | QFile::Text)) { return false; } + QByteArray fc = f.readAll(); + if (fc.isEmpty()) { return false; } + QDomDocument doc; + if (!doc.setContent(fc)) { return false; } + QDomNodeList rules = doc.elementsByTagName("ModelMatchRule"); + if (rules.isEmpty()) { return false; } + + QDomNodeList mmRuleSet = doc.elementsByTagName("ModelMatchRuleSet"); + if (mmRuleSet.size() < 1) { return true; } + + QDomNamedNodeMap attributes = mmRuleSet.at(0).attributes(); + QString folder = attributes.namedItem("Folder").nodeValue().trimmed(); + if (folder.isEmpty()) + { + folder = QFileInfo(fileName).fileName().replace(".vmr", ""); + } + QString updated = attributes.namedItem("UpdatedOn").nodeValue(); + QDateTime qt = QDateTime::fromString(updated); + qint64 updatedTimestamp = qt.toMSecsSinceEpoch(); + + int rulesSize = rules.size(); + for (int i = 0; i < rulesSize; i++) + { + QDomNamedNodeMap attributes = rules.at(i).attributes(); + const QString typeCode = attributes.namedItem("TypeCode").nodeValue(); + const QString modelName = attributes.namedItem("ModelName").nodeValue(); + // remark, callsign prefix is airline ICAO code + const QString callsignPrefix = attributes.namedItem("CallsignPrefix").nodeValue(); + if (modelName.isEmpty()) { continue; } + + // split if we have multiple models + if (modelName.contains("//")) + { + // multiple models + const QStringList models = modelName.split("//"); + for (const QString &model : models) + { + if (model.isEmpty()) { continue; } + CVPilotModelRule rule(model, folder, typeCode, callsignPrefix, updatedTimestamp); + this->m_rules.push_back(rule); + } + } + else + { + // single model + CVPilotModelRule rule(modelName, folder, typeCode, callsignPrefix, updatedTimestamp); + this->m_rules.push_back(rule); + } + } + return true; + } + + } // namespace + } // namespace +} // namespace diff --git a/src/blackmisc/simulation/fscommon/vpilotrulesreader.h b/src/blackmisc/simulation/fscommon/vpilotrulesreader.h new file mode 100644 index 000000000..4afef625d --- /dev/null +++ b/src/blackmisc/simulation/fscommon/vpilotrulesreader.h @@ -0,0 +1,78 @@ +/* Copyright (C) 2015 + * 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_FSCOMMON_VPILOTRULESREADER_H +#define BLACKMISC_SIMULATION_FSCOMMON_VPILOTRULESREADER_H + +#include "blackmisc/blackmiscexport.h" +#include "blackmisc/simulation/fscommon/vpilotmodelruleset.h" +#include +#include + +namespace BlackMisc +{ + namespace Simulation + { + namespace FsCommon + { + //! Model mappings + class BLACKMISC_EXPORT CVPilotRulesReader : public QObject + { + Q_OBJECT + + public: + //! Constructor + CVPilotRulesReader(bool standardDirectory = true, QObject *parent = nullptr); + + //! Destructor + virtual ~CVPilotRulesReader() {} + + //! File names + void addFilename(const QString &fileName); + + //! Directory with .vmr files + void addDirectory(const QString &directory); + + //! Loaded files (number) + int countFilesLoaded() const { return m_loadedFiles; } + + //! Loaded rules + const CVPilotModelRuleSet &getRules() const { return m_rules; } + + //! Loaded rules + int countRulesLoaded() const; + + //! The standard directory for vPilot mappings + static const QString &standardMappingsDirectory(); + + signals: + //! Rules read + void readFinished(bool success); + + public slots: + //! Load data + bool read(); + + 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 + + //! Read single file and do parsing + bool loadFile(const QString &fileName); + + }; + } // namespace + } // namespace +} // namespace + +#endif // guard