From 66075ca0d00000fb2635138792497e4801dd8320 Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Wed, 6 May 2015 02:46:42 +0200 Subject: [PATCH] refs #361, some own ini reader got lost in master, re-applied changes --- .../fscommon/aircraftcfgentries.cpp | 51 ++-- .../simulation/fscommon/aircraftcfgentries.h | 54 ++-- .../fscommon/aircraftcfgentrieslist.cpp | 265 +++++++++++------- .../fscommon/aircraftcfgentrieslist.h | 45 +-- 4 files changed, 244 insertions(+), 171 deletions(-) diff --git a/src/blackmisc/simulation/fscommon/aircraftcfgentries.cpp b/src/blackmisc/simulation/fscommon/aircraftcfgentries.cpp index 8fd42a496..3f000a4dc 100644 --- a/src/blackmisc/simulation/fscommon/aircraftcfgentries.cpp +++ b/src/blackmisc/simulation/fscommon/aircraftcfgentries.cpp @@ -22,19 +22,13 @@ namespace BlackMisc namespace FsCommon { - /* - * Constructor - */ - 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()), + CAircraftCfgEntries::CAircraftCfgEntries(const QString &fileName, qint32 index, const QString &title, const QString &atcType, const QString &atcModel, const QString &atcParkingCode, const QString &description) : + m_index(index), m_fileName(fileName), m_title(title.trimmed()), m_atcType(atcType.trimmed()), m_atcModel(atcModel.trimmed()), m_atcParkingCode(atcParkingCode.trimmed()), m_description(description.trimmed()) { // void } - /* - * String representation - */ QString CAircraftCfgEntries::convertToQString(bool) const { QString s = "{%1, %2, %3, %4, %5, %6}"; @@ -43,9 +37,10 @@ namespace BlackMisc return s; } - /* - * Aircraft model - */ + CAircraftCfgEntries::CAircraftCfgEntries(const QString &fileName, int index) : + m_index(index), m_fileName(fileName) + { } + QString CAircraftCfgEntries::getFileDirectory() const { if (this->m_fileName.isEmpty()) { return ""; } @@ -63,9 +58,31 @@ namespace BlackMisc return d; } - /* - * Convert - */ + void CAircraftCfgEntries::setFileName(const QString &filePath) + { + this->m_fileName = filePath.trimmed(); + } + + void CAircraftCfgEntries::setTitle(const QString &title) + { + this->m_title = title.trimmed(); + } + + void CAircraftCfgEntries::setAtcModel(const QString &atcModel) + { + this->m_atcModel = atcModel.trimmed(); + } + + void CAircraftCfgEntries::setAtcType(const QString &atcType) + { + this->m_atcType = atcType.trimmed(); + } + + void CAircraftCfgEntries::setAtcParkingCode(const QString &parkingCode) + { + this->m_atcParkingCode = parkingCode.trimmed(); + } + CAircraftModel CAircraftCfgEntries::toAircraftModel() const { CAircraftModel model(this->getTitle(), CAircraftModel::TypeModelMapping); @@ -82,9 +99,6 @@ namespace BlackMisc return fn; } - /* - * Get particular column - */ CVariant CAircraftCfgEntries::propertyByIndex(const BlackMisc::CPropertyIndex &index) const { if (index.isMyself()) { return this->toCVariant(); } @@ -112,9 +126,6 @@ namespace BlackMisc } } - /* - * Set property as index - */ void CAircraftCfgEntries::setPropertyByIndex(const CVariant &variant, const BlackMisc::CPropertyIndex &index) { if (index.isMyself()) { this->convertFromCVariant(variant); return; } diff --git a/src/blackmisc/simulation/fscommon/aircraftcfgentries.h b/src/blackmisc/simulation/fscommon/aircraftcfgentries.h index d3cd9b6b9..8e3bec76c 100644 --- a/src/blackmisc/simulation/fscommon/aircraftcfgentries.h +++ b/src/blackmisc/simulation/fscommon/aircraftcfgentries.h @@ -23,11 +23,9 @@ namespace BlackMisc { namespace FsCommon { - /*! - * Set of aircraft.cfg entries representing an aircraft (FSX) - * \remarks an entry in the aircraft.cfg is title, atc type, ... This class already bundles - * relevant entries, hence the class is named Entries (plural) - */ + //! Set of aircraft.cfg entries representing an aircraft (FSX) + //! \remarks an entry in the aircraft.cfg is title, atc type, ... + //! This class already bundles relevant entries, hence the class is named Entries (plural) class BLACKMISC_EXPORT CAircraftCfgEntries: public BlackMisc::CValueObject { public: @@ -47,6 +45,9 @@ namespace BlackMisc //! Default constructor CAircraftCfgEntries() = default; + //! Entries representing an aircraft + CAircraftCfgEntries(const QString &fileName, int index); + //! 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); @@ -83,26 +84,29 @@ namespace BlackMisc //! Texture QString getTexture() const { return this->m_texture; } + //! Is Rotorcraft? + bool isRotorcraft() const { return m_rotorcraft; } + //! Manufacturer + type QString getUiCombinedDescription() const; //! Filepath - void setFileName(const QString &filePath) { this->m_fileName = filePath; } + void setFileName(const QString &filePath); //! Title - void setTitle(const QString &title) { this->m_title = title; } + void setTitle(const QString &title); //! Index void setIndex(int index) { this->m_index = index; } //! ATC model - void setAtcModel(const QString &atcModel) { this->m_atcModel = atcModel.trimmed(); } + void setAtcModel(const QString &atcModel); //! ATC type - void setAtcType(const QString &atcType) { this->m_atcType = atcType.trimmed(); } + void setAtcType(const QString &atcType); //! Parking code - void setAtcParkingCode(const QString &parkingCode) { this->m_atcParkingCode = parkingCode.trimmed(); } + void setAtcParkingCode(const QString &parkingCode); //! Description void setDescription(const QString &description) { this->m_description = description.trimmed(); } @@ -116,6 +120,9 @@ namespace BlackMisc //! UI manufacturer (e.g. Airbus) void setUiManufacturer(const QString &manufacturer) { this->m_uiManufacturer = manufacturer.trimmed(); } + //! Is Rotorcraft? + void setRotorcraft(bool isRotorcraft) { m_rotorcraft = isRotorcraft; } + //! To aircraft model BlackMisc::Simulation::CAircraftModel toAircraftModel() const; @@ -133,20 +140,21 @@ namespace BlackMisc private: BLACK_ENABLE_TUPLE_CONVERSION(CAircraftCfgEntries) - 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 - QString m_texture; //!< texture, needed to identify thumbnail.jpg + int m_index; //!< current index in given config + QString m_fileName; //!< file name of .cfg + QString m_title; //!< Title in .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 + QString m_texture; //!< texture, needed to identify thumbnail.jpg + bool m_rotorcraft = false; //!< hint if rotorcraft }; - } - } -} + } // ns + } // ns +} // ns BLACK_DECLARE_TUPLE_CONVERSION(BlackMisc::Simulation::FsCommon::CAircraftCfgEntries, (o.m_index, o.m_fileName, o.m_title, o.m_atcType, o.m_atcModel, o.m_atcParkingCode)) Q_DECLARE_METATYPE(BlackMisc::Simulation::FsCommon::CAircraftCfgEntries) diff --git a/src/blackmisc/simulation/fscommon/aircraftcfgentrieslist.cpp b/src/blackmisc/simulation/fscommon/aircraftcfgentrieslist.cpp index f34abcfdd..e1fedd1d1 100644 --- a/src/blackmisc/simulation/fscommon/aircraftcfgentrieslist.cpp +++ b/src/blackmisc/simulation/fscommon/aircraftcfgentrieslist.cpp @@ -21,24 +21,38 @@ namespace BlackMisc { namespace Simulation { + namespace FsCommon { + int CAircraftCfgEntriesList::read() + { + if (this->m_readForDirectory) { return this->size(); } + + // not read so far, read it + this->clear(); + this->m_readForDirectory = true; + return this->read(this->m_rootDirectory, excludeDirectories()); + } + + bool CAircraftCfgEntriesList::changeDirectory(const QString &directory) + { + if (this->m_rootDirectory != directory) + { + this->m_rootDirectory = directory; + this->m_readForDirectory = false; + } + return (!directory.isEmpty() && this->existsDir(directory)); + } - /* - * Does the directory exist? - */ bool CAircraftCfgEntriesList::existsDir(const QString &directory) const { QString d = directory.isEmpty() ? this->m_rootDirectory : directory; if (d.isEmpty()) { return false; } QDir dir(d); - //! \todo not available network dir can make this hang here + //! \todo unavailable network dir can make this hang here return dir.exists(); } - /* - * Model for title - */ bool CAircraftCfgEntriesList::containsModelWithTitle(const QString &title, Qt::CaseSensitivity caseSensitivity) { if (title.isEmpty()) { return false; } @@ -47,9 +61,6 @@ namespace BlackMisc ); } - /* - * Double titles - */ QStringList CAircraftCfgEntriesList::detectAmbiguousTitles() const { QStringList titles = this->getTitles(true); @@ -70,9 +81,6 @@ namespace BlackMisc return ambiguousTitles; } - /* - * All titles - */ QStringList CAircraftCfgEntriesList::getTitles(bool sorted) const { QStringList titles = this->transform(Predicates::MemberTransform(&CAircraftCfgEntries::getTitle)); @@ -80,9 +88,6 @@ namespace BlackMisc return titles; } - /* - * As model list - */ CAircraftModelList CAircraftCfgEntriesList::toAircraftModelList() const { CAircraftModelList ml; @@ -93,18 +98,24 @@ namespace BlackMisc return ml; } - /* - * Models for title - */ CAircraftCfgEntriesList CAircraftCfgEntriesList::findByTitle(const QString &title, Qt::CaseSensitivity caseSensitivity) const { return this->findBy([ = ](const CAircraftCfgEntries & entries) -> bool { return title.compare(entries.getTitle(), caseSensitivity) == 0; }); } - /* - * Read all entrities in given directory - */ + const QStringList &CAircraftCfgEntriesList::excludeDirectories() + { + static const QStringList exclude + { + // "SimObjects/Misc", + "SimObjects/Animals", + "SimObjects/GroundVehicles", + "SimObjects/Boats" + }; + return exclude; + } + int CAircraftCfgEntriesList::read(const QString &directory, const QStringList &excludeDirectories) { if (m_cancelRead) { return -1; } @@ -121,104 +132,168 @@ namespace BlackMisc // 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 int counter = 0; QString currentDir = dir.absolutePath(); - // Dirs last is crucial,since I will break recursion on "aircraft.cfg" level + // Dirs last is crucial, since I will break recursion on ".cfg" level + // once I have found .cfg, I do not go any deeper QFileInfoList files = dir.entryInfoList(QDir::Files | QDir::AllDirs, QDir::DirsLast); - for (const QFileInfo &file : files) { if (m_cancelRead) { return -1; } if (file.isDir()) { QString nextDir = file.absoluteFilePath(); - if (currentDir.startsWith(nextDir, Qt::CaseInsensitive)) continue; // do not go up + if (currentDir.startsWith(nextDir, Qt::CaseInsensitive)) { continue; } // do not go up if (dir == currentDir) { continue; } // do not recursively call same directory counter += CAircraftCfgEntriesList::read(nextDir, excludeDirectories); } else { - // due to the filter we expect only "aircraft.cfg" here - QString path = file.absoluteFilePath(); - - // 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) + // due to the filter we expect only ".cfg" here + // 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(); + QFile file(fileName); + if (!file.open(QFile::ReadOnly | QFile::Text)) { - if (m_cancelRead) { return -1; } - QString group = QString("fltsim.%1").arg(index); - aircraftCfg.beginGroup(group); - - // does group exist? - if (aircraftCfg.contains("title")) - { - 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")); - entry.setTexture(fixedStringContent(aircraftCfg, "texture")); - 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(); + CLogMessage(this).warning("Unable to read file %1") << fileName; + continue; } - break; - } - } + QTextStream in(&file); + QList tempEntries; + + // parse through the file + QString atcType; + QString atcModel; + QString fltSection("[FLTSIM.0]"); + int fltsimCounter = 0; + FileSection currentSection = Unknown; + bool isRotorcraftPath = fileName.toLower().contains("rotorcraft"); + + while (!in.atEnd()) + { + const QString lineFixed(in.readLine().trimmed()); + if (lineFixed.isEmpty()) { continue; } + if (lineFixed.startsWith("[")) + { + if (lineFixed.startsWith("[GENERAL]", Qt::CaseInsensitive)) { currentSection = General; continue; } + if (lineFixed.startsWith(fltSection, Qt::CaseInsensitive)) + { + CAircraftCfgEntries e(fileName, fltsimCounter); + if (isRotorcraftPath) + { + e.setRotorcraft(true); + } + tempEntries.append(e); + currentSection = Fltsim; + fltSection = QString("[FLTSIM.%1]").arg(++fltsimCounter); + continue; + } + currentSection = Unknown; + continue; + } + switch (currentSection) + { + case General: + { + if (lineFixed.startsWith("//")) { break; } + if (atcType.isEmpty() || atcModel.isEmpty()) + { + QString c = getFixedIniLineContent(lineFixed); + if (lineFixed.startsWith("atc_type", Qt::CaseInsensitive)) { atcType = c; } + else if (lineFixed.startsWith("atc_model", Qt::CaseInsensitive)) { atcModel = c; } + } + } + break; + case Fltsim: + { + if (lineFixed.startsWith("//")) { break; } + CAircraftCfgEntries &e = tempEntries[tempEntries.size() - 1]; + if (lineFixed.startsWith("atc_parking_codes", Qt::CaseInsensitive)) + { + e.setAtcParkingCode(getFixedIniLineContent(lineFixed)); + } + else if (lineFixed.startsWith("description", Qt::CaseInsensitive)) + { + e.setDescription(getFixedIniLineContent(lineFixed)); + } + else if (lineFixed.startsWith("ui_manufacturer", Qt::CaseInsensitive)) + { + e.setUiManufacturer(getFixedIniLineContent(lineFixed)); + } + else if (lineFixed.startsWith("ui_typerole", Qt::CaseInsensitive)) + { + bool r = getFixedIniLineContent(lineFixed).toLower().contains("rotor"); + e.setRotorcraft(r); + } + else if (lineFixed.startsWith("ui_type", Qt::CaseInsensitive)) + { + e.setUiType(getFixedIniLineContent(lineFixed)); + } + else if (lineFixed.startsWith("texture", Qt::CaseInsensitive)) + { + e.setTexture(getFixedIniLineContent(lineFixed)); + } + else if (lineFixed.startsWith("title", Qt::CaseInsensitive)) + { + e.setTitle(getFixedIniLineContent(lineFixed)); + } + } + break; + default: + case Unknown: break; + } + + } // all lines + file.close(); + + // store all entries + for (const CAircraftCfgEntries &e : tempEntries) + { + if (e.getTitle().isEmpty()) + { + CLogMessage(this).info("FSX model in %1, index %2 has no title") << fileName << e.getIndex(); + continue; + } + CAircraftCfgEntries newEntries(e); + newEntries.setAtcModel(atcModel); + newEntries.setAtcType(atcType); + this->push_back(newEntries); + counter++; + } + return counter; // do not go any deeper in file tree, we found aircraft.cfg + + } // file, no directory + } // files return counter; } - QString CAircraftCfgEntriesList::fixedStringContent(const QSettings &settings, const QString &key) + QString CAircraftCfgEntriesList::getFixedIniLineContent(const QString &line) { - return fixedStringContent(settings.value(key)); + if (line.isEmpty()) { return ""; } + int index = line.indexOf('='); + if (index < 0) { return ""; } + if (line.length() < index + 1) { return ""; } + + QString content(line.mid(index + 1).trimmed()); + + // fix "" strings, some are malformed and just contain " at beginning, end + if (content.endsWith('"')) { content.remove(content.size() - 1 , 1); } + if (content.startsWith('"')) { content.remove(0 , 1); } + + // fix C style linebreaks + content.replace("\\n", " "); + content.replace("\\t", " "); + + // return + return content; } - QString CAircraftCfgEntriesList::fixedStringContent(const QVariant &qv) - { - if (qv.isNull() || !qv.isValid()) - { - return ""; // normal when there is no settings value - } - else if (static_cast(qv.type()) == QMetaType::QStringList) - { - QStringList l = qv.toStringList(); - return l.join(",").trimmed(); - } - else if (static_cast(qv.type()) == QMetaType::QString) - { - return qv.toString().trimmed(); - } - Q_ASSERT(false); - return ""; - } - - /* - * Register metadata - */ void CAircraftCfgEntriesList::registerMetadata() { qRegisterMetaType>(); diff --git a/src/blackmisc/simulation/fscommon/aircraftcfgentrieslist.h b/src/blackmisc/simulation/fscommon/aircraftcfgentrieslist.h index 606441dcf..d8fd62b2c 100644 --- a/src/blackmisc/simulation/fscommon/aircraftcfgentrieslist.h +++ b/src/blackmisc/simulation/fscommon/aircraftcfgentrieslist.h @@ -39,26 +39,10 @@ namespace BlackMisc 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(); } - - // not read so far, read it - this->clear(); - this->m_readForDirectory = true; - return this->read(this->m_rootDirectory, excludeDirectories()); - } + int read(); //! Change the directory - bool changeDirectory(const QString &directory) - { - if (this->m_rootDirectory != directory) - { - this->m_rootDirectory = directory; - this->m_readForDirectory = false; - } - return (!directory.isEmpty() && this->existsDir(directory)); - } + bool changeDirectory(const QString &directory); //! Virtual destructor virtual ~CAircraftCfgEntriesList() {} @@ -97,17 +81,7 @@ namespace BlackMisc void convertFromQVariant(const QVariant &variant) { BlackMisc::setFromQVariant(this, variant); } //! Do not include the following directories for FS - static const QStringList &excludeDirectories() - { - static const QStringList exclude - { - "SimObjects/Animals", - "SimObjects/Misc", - "SimObjects/GroundVehicles", - "SimObjects/Boats" - }; - return exclude; - } + static const QStringList &excludeDirectories(); //! Register metadata static void registerMetadata(); @@ -120,11 +94,16 @@ namespace BlackMisc //! Read all entries in one directory int read(const QString &directory, const QStringList &excludeDirectories = QStringList()); - //! Fix the content read - static QString fixedStringContent(const QVariant &qv); + //! Section within file + enum FileSection + { + General, + Fltsim, + Unknown + }; - //! Value from settings, fixed string - static QString fixedStringContent(const QSettings &settings, const QString &key); + //! Content after "=" + static QString getFixedIniLineContent(const QString &line); }; } // namespace } // namespace