From 3cdc485e56c588efbe76052566b6b8b7ad1e8844 Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Mon, 15 Dec 2014 00:32:20 +0100 Subject: [PATCH] refs #358, extended FS specific class for cfg entries * more details fetched * conversion to aircraft model / aircraft mode list (FS specific to generic) * detect functions to find possible trouble makers --- src/blacksim/fscommon/aircraftcfgentries.cpp | 41 ++++-- src/blacksim/fscommon/aircraftcfgentries.h | 71 +++++++---- .../fscommon/aircraftcfgentrieslist.cpp | 119 ++++++++++++++++-- .../fscommon/aircraftcfgentrieslist.h | 36 ++++-- 4 files changed, 216 insertions(+), 51 deletions(-) diff --git a/src/blacksim/fscommon/aircraftcfgentries.cpp b/src/blacksim/fscommon/aircraftcfgentries.cpp index 189aa4c6c..cab41eb95 100644 --- a/src/blacksim/fscommon/aircraftcfgentries.cpp +++ b/src/blacksim/fscommon/aircraftcfgentries.cpp @@ -12,6 +12,7 @@ #include "blackmisc/variant.h" using namespace BlackMisc; +using namespace BlackMisc::Network; namespace BlackSim { @@ -21,9 +22,9 @@ namespace BlackSim /* * Constructor */ - CAircraftCfgEntries::CAircraftCfgEntries(const QString &filePath, qint32 index, const QString &title, const QString &atcType, const QString &atcModel, const QString &atcParkingCode) : - m_index(index), m_filePath(filePath), m_title(title), m_atcType(atcType), - m_atcModel(atcModel), m_atcParkingCode(atcParkingCode) + CAircraftCfgEntries::CAircraftCfgEntries(const QString &filePath, qint32 index, const QString &title, const QString &atcType, const QString &atcModel, const QString &atcParkingCode, const QString &description) : + m_index(index), m_fileName(filePath), m_title(title.trimmed()), m_atcType(atcType.trimmed()), + m_atcModel(atcModel.trimmed()), m_atcParkingCode(atcParkingCode.trimmed()), m_description(description.trimmed()) { // void } @@ -34,11 +35,35 @@ namespace BlackSim QString CAircraftCfgEntries::convertToQString(bool) const { QString s = "{%1, %2, %3, %4, %5, %6}"; - s = s.arg(this->m_filePath).arg(this->m_index).arg(this->m_title) + s = s.arg(this->m_fileName).arg(this->m_index).arg(this->m_title) .arg(this->m_atcModel).arg(this->m_atcType).arg(this->m_atcParkingCode); return s; } + /* + * Aircraft model + */ + QString CAircraftCfgEntries::getUiCombinedDescription() const + { + QString d(this->m_uiManufacturer); + if (m_uiType.isEmpty()) { return d; } + if (d.isEmpty()) { return m_uiType; } + d += " "; + d += m_uiType; + return d; + } + + /* + * Convert + */ + CAircraftModel CAircraftCfgEntries::toAircraftModel() const + { + CAircraftModel model(this->getTitle(), CAircraftModel::TypeModelMapping); + model.setDescription(this->getUiCombinedDescription()); + model.setFileName(this->getFileName()); + return model; + } + /* * Get particular column */ @@ -48,8 +73,8 @@ namespace BlackSim ColumnIndex i = index.frontCasted(); switch (i) { - case IndexFilePath: - return CVariant::from(this->m_filePath); + case IndexFileName: + return CVariant::from(this->m_fileName); case IndexTitle: return CVariant::from(this->m_title); case IndexAtcType: @@ -83,8 +108,8 @@ namespace BlackSim case IndexEntryIndex: this->setIndex(variant.toInt()); break; - case IndexFilePath: - this->setFilePath(variant.toQString()); + case IndexFileName: + this->setFileName(variant.toQString()); break; case IndexParkingCode: this->setAtcParkingCode(variant.toQString()); diff --git a/src/blacksim/fscommon/aircraftcfgentries.h b/src/blacksim/fscommon/aircraftcfgentries.h index f85534660..2ee5162ed 100644 --- a/src/blacksim/fscommon/aircraftcfgentries.h +++ b/src/blacksim/fscommon/aircraftcfgentries.h @@ -13,6 +13,8 @@ #define BLACKSIM_FSCOMMON_AIRCRAFTCFGENTRY_H #include "blackmisc/propertyindex.h" +#include "blackmisc/nwaircraftmodel.h" +#include "blackmisc/variant.h" namespace BlackSim { @@ -30,29 +32,22 @@ namespace BlackSim enum ColumnIndex { IndexEntryIndex = BlackMisc::CPropertyIndex::GlobalIndexCAircraftCfgEntries, - IndexFilePath, + IndexFileName, IndexTitle, IndexAtcType, IndexAtcModel, - IndexParkingCode + IndexParkingCode, + IndexDescription }; //! Default constructor CAircraftCfgEntries() = default; - /*! - * Entries representing an aircraft - * \param filePath - * \param index - * \param title - * \param atcType - * \param atcModel - * \param atcParkingCode - */ - CAircraftCfgEntries(const QString &filePath, int index, const QString &title, const QString &atcType, const QString &atcModel, const QString &atcParkingCode); + //! Entries representing an aircraft + CAircraftCfgEntries(const QString &filePath, int index, const QString &title, const QString &atcType, const QString &atcModel, const QString &atcParkingCode, const QString &description); - //! Filepath - QString getFilePath() const { return this->m_filePath; } + //! File name + QString getFileName() const { return this->m_fileName; } //! Title QString getTitle() const { return this->m_title; } @@ -66,11 +61,23 @@ namespace BlackSim //! ATC type QString getAtcType() const { return this->m_atcType; } + //! Description + QString getDescription() const { return this->m_description; } + //! ATC parking code QString getAtcParkingCode() const { return this->m_atcParkingCode; } + //! UI type (e.g. A321-231 IAE) + QString getUiType() const { return this->m_uiType; } + + //! UI manufacturer (e.g. Airbus) + QString getUiManufacturer() const { return this->m_uiManufacturer; } + + //! Manufacturer + type + QString getUiCombinedDescription() const; + //! Filepath - void setFilePath(const QString &filePath) { this->m_filePath = filePath; } + void setFileName(const QString &filePath) { this->m_fileName = filePath; } //! Title void setTitle(const QString &title) { this->m_title = title; } @@ -79,13 +86,25 @@ namespace BlackSim void setIndex(int index) { this->m_index = index; } //! ATC model - void setAtcModel(const QString &atcModel) { this->m_atcModel = atcModel; } + void setAtcModel(const QString &atcModel) { this->m_atcModel = atcModel.trimmed(); } //! ATC type - void setAtcType(const QString &atcType) { this->m_atcType = atcType; } + void setAtcType(const QString &atcType) { this->m_atcType = atcType.trimmed(); } //! Parking code - void setAtcParkingCode(const QString &parkingCode) { this->m_atcParkingCode = parkingCode; } + void setAtcParkingCode(const QString &parkingCode) { this->m_atcParkingCode = parkingCode.trimmed(); } + + //! Description + void setDescription(const QString &description) { this->m_description = description.trimmed(); } + + //! UI type (e.g. A321-231 IAE) + void setUiType(const QString &type) { this->m_uiType = type.trimmed(); } + + //! UI manufacturer (e.g. Airbus) + void setUiManufacturer(const QString &manufacturer) { this->m_uiManufacturer = manufacturer.trimmed(); } + + //! To aircraft model + BlackMisc::Network::CAircraftModel toAircraftModel() const; //! \copydoc CValueObject::propertyByIndex virtual BlackMisc::CVariant propertyByIndex(const BlackMisc::CPropertyIndex &index) const override; @@ -99,18 +118,20 @@ namespace BlackSim private: BLACK_ENABLE_TUPLE_CONVERSION(CAircraftCfgEntries) - int m_index; //!< current index in given config - QString m_filePath; //!< file path of aircraft.cfg - QString m_title; //!< Title in aircraft.cfg - QString m_atcType; //!< ATC type - QString m_atcModel; //!< ATC model + int m_index; //!< current index in given config + QString m_fileName; //!< file name of aircraft.cfg + QString m_title; //!< Title in aircraft.cfg + QString m_atcType; //!< ATC type + QString m_atcModel; //!< ATC model QString m_atcParkingCode; //!< ATC parking code - + QString m_description; //!< descriptive text + QString m_uiType; //!< e.g. A321-231 IAE + QString m_uiManufacturer; //!< e.g. Airbus }; } } -BLACK_DECLARE_TUPLE_CONVERSION(BlackSim::FsCommon::CAircraftCfgEntries, (o.m_index, o.m_filePath, o.m_title, o.m_atcType, o.m_atcModel, o.m_atcParkingCode)) +BLACK_DECLARE_TUPLE_CONVERSION(BlackSim::FsCommon::CAircraftCfgEntries, (o.m_index, o.m_fileName, o.m_title, o.m_atcType, o.m_atcModel, o.m_atcParkingCode)) Q_DECLARE_METATYPE(BlackSim::FsCommon::CAircraftCfgEntries) #endif // guard diff --git a/src/blacksim/fscommon/aircraftcfgentrieslist.cpp b/src/blacksim/fscommon/aircraftcfgentrieslist.cpp index 8a97b2b1b..c2a38b76a 100644 --- a/src/blacksim/fscommon/aircraftcfgentrieslist.cpp +++ b/src/blacksim/fscommon/aircraftcfgentrieslist.cpp @@ -8,6 +8,13 @@ */ #include "aircraftcfgentrieslist.h" +#include "blackmisc/predicates.h" +#include "blackmisc/logmessage.h" +#include +#include + +using namespace BlackMisc; +using namespace BlackMisc::Network; namespace BlackSim { @@ -20,9 +27,10 @@ namespace BlackSim bool CAircraftCfgEntriesList::existsDir(const QString &directory) const { QString d = directory.isEmpty() ? this->m_rootDirectory : directory; - if (d.isEmpty()) return false; + if (d.isEmpty()) { return false; } QDir dir(d); - return (dir.exists()); + //! \todo not available network dir can make this hang here + return dir.exists(); } /* @@ -30,14 +38,62 @@ namespace BlackSim */ bool CAircraftCfgEntriesList::containsModelWithTitle(const QString &title, Qt::CaseSensitivity caseSensitivity) { - return this->containsBy([ = ](const CAircraftCfgEntries & entries) -> bool - { return title.compare(entries.getTitle(), caseSensitivity) == 0; }); + if (title.isEmpty()) { return false; } + return this->containsBy( + [ = ](const CAircraftCfgEntries & entries) -> bool { return title.compare(entries.getTitle(), caseSensitivity) == 0; } + ); + } + + /* + * Double titles + */ + QStringList CAircraftCfgEntriesList::detectAmbiguousTitles() const + { + QStringList titles = this->getTitles(true); + QStringList ambiguousTitles; + QString last; + foreach(QString title, titles) + { + if (title.isEmpty()) { continue; } + if (title.compare(last, Qt::CaseInsensitive) == 0) + { + if (!ambiguousTitles.contains(title, Qt::CaseInsensitive)) + { + ambiguousTitles.append(title); + } + } + last = title; + } + return ambiguousTitles; + } + + /* + * All titles + */ + QStringList CAircraftCfgEntriesList::getTitles(bool sorted) const + { + QStringList titles = this->transform(Predicates::MemberTransform(&CAircraftCfgEntries::getTitle)); + if (sorted) { titles.sort(Qt::CaseInsensitive); } + return titles; + } + + /* + * As model list + */ + CAircraftModelList CAircraftCfgEntriesList::toAircraftModelList() const + { + CAircraftModelList ml; + for (auto it = this->begin() ; it != this->end(); ++it) + { + ml.push_back(it->toAircraftModel()); + } + return ml; } /* * Models for title */ - CAircraftCfgEntriesList CAircraftCfgEntriesList::findByTitle(const QString &title, Qt::CaseSensitivity caseSensitivity) + CAircraftCfgEntriesList CAircraftCfgEntriesList::findByTitle(const QString &title, Qt::CaseSensitivity caseSensitivity) const { return this->findBy([ = ](const CAircraftCfgEntries & entries) -> bool { return title.compare(entries.getTitle(), caseSensitivity) == 0; }); @@ -48,6 +104,8 @@ namespace BlackSim */ int CAircraftCfgEntriesList::read(const QString &directory) { + if (m_cancelRead) { return -1; } + // set directory with name filters, get aircraft.cfg and sub directories QDir dir(directory, "aircraft.cfg", QDir::Name, QDir::Files | QDir::AllDirs); if (!dir.exists()) return 0; // can happen if there are shortcuts or linked dirs not available @@ -60,6 +118,7 @@ namespace BlackSim foreach(QFileInfo file, files) { + if (m_cancelRead) { return -1; } if (file.isDir()) { QString nextDir = file.absoluteFilePath(); @@ -74,28 +133,44 @@ namespace BlackSim // I abuse the QSettings as ini-file reader QSettings aircraftCfg(path, QSettings::IniFormat); + + // from the general section const QString atcType = aircraftCfg.value("atc_type").toString(); const QString atcModel = aircraftCfg.value("atc_model").toString(); int index = 0; while (index >= 0) { + if (m_cancelRead) { return -1; } QString group = QString("fltsim.%1").arg(index); aircraftCfg.beginGroup(group); + + // does group exist? if (aircraftCfg.contains("title")) { - CAircraftCfgEntries entry(path, index, "", atcType, atcModel, ""); - entry.setTitle(aircraftCfg.value("title").toString()); - entry.setAtcParkingCode(aircraftCfg.value("atc_parking_codes").toString()); - this->push_back(entry); - aircraftCfg.endGroup(); + QString title = fixedStringContent(aircraftCfg, "title"); + if (!title.isEmpty()) + { + CAircraftCfgEntries entry(path, index, title, atcType, atcModel, "", ""); + entry.setAtcParkingCode(fixedStringContent(aircraftCfg, "atc_parking_codes")); + entry.setDescription(fixedStringContent(aircraftCfg, "description")); + entry.setUiManufacturer(fixedStringContent(aircraftCfg, "ui_manufacturer")); + entry.setUiType(fixedStringContent(aircraftCfg, "ui_type")); + this->push_back(entry); + } + else + { + CLogMessage(this).info("FSX model in %1, index %2 has no title") << path << index; + } ++index; ++counter; } else { + // marks end of the "fltsim.x" groups index = -1; } + aircraftCfg.endGroup(); } break; } @@ -103,6 +178,30 @@ namespace BlackSim return counter; } + QString CAircraftCfgEntriesList::fixedStringContent(const QSettings &settings, const QString &key) + { + return fixedStringContent(settings.value(key)); + } + + QString CAircraftCfgEntriesList::fixedStringContent(const QVariant &qv) + { + if (qv.isNull() || !qv.isValid()) + { + return ""; // normal when there is no settings value + } + else if (qv.type() == QMetaType::QStringList) + { + QStringList l = qv.toStringList(); + return l.join(",").trimmed(); + } + else if (qv.type() == QMetaType::QString) + { + return qv.toString().trimmed(); + } + Q_ASSERT(false); + return ""; + } + /* * Register metadata */ diff --git a/src/blacksim/fscommon/aircraftcfgentrieslist.h b/src/blacksim/fscommon/aircraftcfgentrieslist.h index bda4c75fe..8275c464f 100644 --- a/src/blacksim/fscommon/aircraftcfgentrieslist.h +++ b/src/blacksim/fscommon/aircraftcfgentrieslist.h @@ -9,12 +9,14 @@ //! \file -#ifndef BLACKSIM_FSCOMMON_AIRCRAFTCFG_H -#define BLACKSIM_FSCOMMON_AIRCRAFTCFG_H +#ifndef BLACKSIM_FSCOMMON_AIRCRAFTCFGLIST_H +#define BLACKSIM_FSCOMMON_AIRCRAFTCFGLIST_H #include "aircraftcfgentries.h" #include "blackmisc/sequence.h" #include "blackmisc/collection.h" +#include "blackmisc/nwaircraftmodellist.h" + #include #include #include @@ -32,12 +34,12 @@ namespace BlackSim public: //! Constructor - CAircraftCfgEntriesList(const QString &rootDirectory = "") : m_rootDirectory(rootDirectory), m_readForDirectory(false) {} + CAircraftCfgEntriesList(const QString &rootDirectory = "") : m_rootDirectory(rootDirectory) {} //! Read all aircraft.cfg files starting from root directory int read() { - if (this->m_readForDirectory) return this->size(); + if (this->m_readForDirectory) { return this->size(); } // not read so far, read it this->clear(); @@ -53,7 +55,7 @@ namespace BlackSim this->m_rootDirectory = directory; this->m_readForDirectory = false; } - return !directory.isEmpty() && this->existsDir(directory); + return (!directory.isEmpty() && this->existsDir(directory)); } //! Virtual destructor @@ -65,14 +67,26 @@ namespace BlackSim //! Has current directory been read? bool hasReadDirectory() const { return this->m_readForDirectory; } + //! Cancel read + void cancelRead() { m_cancelRead = true; } + //! Current root directory QString getRootDirectory() const { return this->m_rootDirectory; } //! Contains model with title? bool containsModelWithTitle(const QString &title, Qt::CaseSensitivity caseSensitivity = Qt::CaseInsensitive); + //! All titles (aka model names) + QStringList getTitles(bool sorted = false) const; + + //! As aircraft models + BlackMisc::Network::CAircraftModelList toAircraftModelList() const; + + //! Ambiguous titles + QStringList detectAmbiguousTitles() const; + //! Find by title - CAircraftCfgEntriesList findByTitle(const QString &title, Qt::CaseSensitivity caseSensitivity); + CAircraftCfgEntriesList findByTitle(const QString &title, Qt::CaseSensitivity caseSensitivity) const; //! \copydoc CValueObject::toQVariant virtual QVariant toQVariant() const override { return QVariant::fromValue(*this); } @@ -91,12 +105,18 @@ namespace BlackSim static void registerMetadata(); private: - QString m_rootDirectory; //!< root directory reading aircraft.cfg files - bool m_readForDirectory; //!< valid read for given directory + QString m_rootDirectory; //!< root directory reading aircraft.cfg files + bool m_readForDirectory = false; //!< valid read for given directory + bool m_cancelRead = false; //! Read all entries in one directory int read(const QString &directory); + //! Fix the content read + static QString fixedStringContent(const QVariant &qv); + + //! Value from settings, fixed string + static QString fixedStringContent(const QSettings &settings, const QString &key); }; } // namespace } // namespace