refs #452, improved FSX aircraft cfg data / cfg parser

* new attributes (e.g. "created by")
* conversion to CAircraftModel
* using interface in CAircraftCfgParser
* new utility methods in FS utility class
* adjusted model mappings provider
This commit is contained in:
Klaus Basan
2015-09-23 16:36:06 +02:00
committed by Mathew Sutcliffe
parent ab8828f177
commit 5223d2fbd8
11 changed files with 340 additions and 77 deletions

View File

@@ -12,6 +12,7 @@
#include "blackmisc/variant.h"
using namespace BlackMisc;
using namespace BlackMisc::Aviation;
using namespace BlackMisc::Simulation;
using namespace BlackMisc::Network;
@@ -83,11 +84,57 @@ namespace BlackMisc
this->m_atcParkingCode = parkingCode.trimmed();
}
void CAircraftCfgEntries::setAtcAirline(const QString &airline)
{
this->m_atcAirline = airline.trimmed();
}
void CAircraftCfgEntries::setSimName(const QString &simName)
{
this->m_simName = simName.trimmed();
}
void CAircraftCfgEntries::setDescription(const QString &description)
{
this->m_description = description.trimmed();
}
void CAircraftCfgEntries::setCreatedBy(const QString &createdBy)
{
this->m_createdBy = createdBy.trimmed();
}
void CAircraftCfgEntries::setTexture(const QString &texture)
{
this->m_texture = texture.trimmed();
}
void CAircraftCfgEntries::setUiType(const QString &type)
{
this->m_uiType = type.trimmed();
}
CAircraftModel CAircraftCfgEntries::toAircraftModel() const
{
CAircraftModel model(this->getTitle(), CAircraftModel::TypeModelMapping);
model.setDescription(this->getUiCombinedDescription());
CAircraftModel model(this->getTitle(), CAircraftModel::TypeOwnSimulatorModel);
model.setDescription(this->getUiCombinedDescription()); // Manufacturer and type
model.setFileName(this->getFileName());
model.setName(this->getSimName());
CAircraftIcaoCode aircraft(getAtcModel());
aircraft.setManufacturer(this->getUiManufacturer());
model.setAircraftIcaoCode(aircraft);
CLivery livery;
livery.setCombinedCode(this->getTexture());
CAirlineIcaoCode airline;
airline.setName(this->getAtcAirline());
livery.setAirlineIcaoCode(airline);
model.setLivery(livery);
CDistributor distributor(this->getCreatedBy());
model.setDistributor(distributor);
return model;
}

View File

@@ -52,37 +52,46 @@ namespace BlackMisc
CAircraftCfgEntries(const QString &filePath, int index, const QString &title, const QString &atcType, const QString &atcModel, const QString &atcParkingCode, const QString &description);
//! File name
QString getFileName() const { return this->m_fileName; }
const QString &getFileName() const { return this->m_fileName; }
//! Directory of entry
QString getFileDirectory() const;
//! Title
QString getTitle() const { return this->m_title; }
const QString &getTitle() const { return this->m_title; }
//! Index
int getIndex() const { return this->m_index; }
//! ATC model
QString getAtcModel() const { return this->m_atcModel; }
const QString &getAtcModel() const { return this->m_atcModel; }
//! ATC type
QString getAtcType() const { return this->m_atcType; }
const QString &getAtcType() const { return this->m_atcType; }
//! ATC airline
const QString &getAtcAirline() const { return this->m_atcAirline; }
//! Sim name
const QString &getSimName() const { return this->m_simName; }
//! Description
QString getDescription() const { return this->m_description; }
const QString &getDescription() const { return this->m_description; }
//! ATC parking code
QString getAtcParkingCode() const { return this->m_atcParkingCode; }
const QString &getAtcParkingCode() const { return this->m_atcParkingCode; }
//! UI type (e.g. A321-231 IAE)
QString getUiType() const { return this->m_uiType; }
const QString &getUiType() const { return this->m_uiType; }
//! UI manufacturer (e.g. Airbus)
QString getUiManufacturer() const { return this->m_uiManufacturer; }
const QString &getUiManufacturer() const { return this->m_uiManufacturer; }
//! Texture
QString getTexture() const { return this->m_texture; }
const QString &getTexture() const { return this->m_texture; }
//! Created by
const QString &getCreatedBy() const { return this->m_createdBy; }
//! Is Rotorcraft?
bool isRotorcraft() const { return m_rotorcraft; }
@@ -108,14 +117,23 @@ namespace BlackMisc
//! Parking code
void setAtcParkingCode(const QString &parkingCode);
//! Airline
void setAtcAirline(const QString &airline);
//! Simulator name
void setSimName(const QString &simName);
//! Description
void setDescription(const QString &description) { this->m_description = description.trimmed(); }
void setDescription(const QString &description);
//! Created by
void setCreatedBy(const QString &createdBy);
//! Texture
void setTexture(const QString &texture) { this->m_texture = texture; }
void setTexture(const QString &texture);
//! UI type (e.g. A321-231 IAE)
void setUiType(const QString &type) { this->m_uiType = type.trimmed(); }
void setUiType(const QString &type);
//! UI manufacturer (e.g. Airbus)
void setUiManufacturer(const QString &manufacturer) { this->m_uiManufacturer = manufacturer.trimmed(); }
@@ -145,11 +163,14 @@ namespace BlackMisc
QString m_title; //!< Title in .cfg
QString m_atcType; //!< ATC type
QString m_atcModel; //!< ATC model
QString m_atcAirline; //!< ATC airline
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
QString m_simName; //!< name in simulator
QString m_createdBy; //!< created by, "distributor"
bool m_rotorcraft = false; //!< hint if rotorcraft
};
} // ns

View File

@@ -70,6 +70,18 @@ namespace BlackMisc
return ml;
}
CAircraftModelList CAircraftCfgEntriesList::toAircraftModelList(const CSimulatorInfo &simInfo) const
{
CAircraftModelList ml;
for (auto it = this->begin() ; it != this->end(); ++it)
{
CAircraftModel m(it->toAircraftModel());
m.setSimulatorInfo(simInfo);
ml.push_back(m);
}
return ml;
}
CAircraftCfgEntriesList CAircraftCfgEntriesList::findByTitle(const QString &title, Qt::CaseSensitivity caseSensitivity) const
{
return this->findBy([ = ](const CAircraftCfgEntries & entries) -> bool

View File

@@ -51,6 +51,9 @@ namespace BlackMisc
//! As aircraft models
BlackMisc::Simulation::CAircraftModelList toAircraftModelList() const;
//! As aircraft models for simulator
BlackMisc::Simulation::CAircraftModelList toAircraftModelList(const BlackMisc::Simulation::CSimulatorInfo &simInfo) const;
//! Ambiguous titles
QStringList detectAmbiguousTitles() const;
@@ -58,7 +61,6 @@ namespace BlackMisc
CAircraftCfgEntriesList findByTitle(const QString &title, Qt::CaseSensitivity caseSensitivity = Qt::CaseInsensitive) const;
private:
//! Section within file
enum FileSection
{
@@ -66,7 +68,6 @@ namespace BlackMisc
Fltsim,
Unknown
};
};
} // namespace
} // namespace

View File

@@ -8,11 +8,13 @@
*/
#include "aircraftcfgparser.h"
#include "blackmisc/simulation/fscommon/fscommonutil.h"
#include "blackmisc/predicates.h"
#include "blackmisc/logmessage.h"
using namespace BlackMisc;
using namespace BlackMisc::Simulation;
using namespace BlackMisc::Simulation::FsCommon;
using namespace BlackMisc::Network;
namespace BlackMisc
@@ -21,6 +23,43 @@ 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::createModelLoader(const CSimulatorInfo &simInfo)
{
if (simInfo.fsx())
{
return new CAircraftCfgParser(
CSimulatorInfo(CSimulatorInfo::FSX),
CFsCommonUtil::fsxSimObjectsDir(),
CFsCommonUtil::fsxSimObjectsExcludeDirectories());
}
else if (simInfo.fs9())
{
return new CAircraftCfgParser(
CSimulatorInfo(CSimulatorInfo::FS9),
CFsCommonUtil::fs9AircraftDir(),
CFsCommonUtil::fs9AircraftObjectsExcludeDirectories());
}
else if (simInfo.p3d())
{
return new CAircraftCfgParser(
CSimulatorInfo(CSimulatorInfo::P3D),
CFsCommonUtil::p3dSimObjectsDir(),
CFsCommonUtil::p3dSimObjectsExcludeDirectories());
}
Q_ASSERT_X(false, Q_FUNC_INFO, "Illegal simulator info");
return nullptr;
}
CAircraftCfgParser::~CAircraftCfgParser()
{
// that should be safe as long as the worker uses deleteLater (which it does)
@@ -36,9 +75,37 @@ namespace BlackMisc
return true;
}
void CAircraftCfgParser::parse(ParserMode mode)
CPixmap CAircraftCfgParser::iconForModel(const QString &modelString, CStatusMessage &statusMessage) const
{
if (mode == ModeAsync)
static const CPixmap empty;
if (modelString.isEmpty()) { return empty; }
CAircraftCfgEntriesList cfgEntries = this->getAircraftCfgEntriesList().findByTitle(modelString);
if (cfgEntries.isEmpty())
{
statusMessage = CStatusMessage(CStatusMessage::SeverityWarning, QString("No .cfg entry for '%1'").arg(modelString));
return empty;
}
// normally we should have only one entry
if (cfgEntries.size() > 1)
{
statusMessage = CStatusMessage(CStatusMessage::SeverityWarning, QString("Multiple FSX .cfg entries for '%1'").arg(modelString));
}
// use first with icon
for (const CAircraftCfgEntries &entry : cfgEntries)
{
const QString thumbnail = entry.getThumbnailFileName();
if (thumbnail.isEmpty()) { continue; }
QPixmap pm;
if (pm.load(thumbnail)) { return CPixmap(pm); }
}
return empty;
}
void CAircraftCfgParser::startLoading(LoadMode mode)
{
if (mode == ModeBackground)
{
if (m_parserWorker && !m_parserWorker->isFinished()) { return; }
auto rootDirectory = m_rootDirectory;
@@ -47,7 +114,7 @@ namespace BlackMisc
[this, rootDirectory, excludedDirectories]()
{
bool ok;
auto aircraftCfgEntriesList = this->parseImpl(rootDirectory, excludedDirectories, &ok);
auto aircraftCfgEntriesList = this->performParsing(rootDirectory, excludedDirectories, &ok);
return std::make_pair(aircraftCfgEntriesList, ok);
});
m_parserWorker->thenWithResult<std::pair<CAircraftCfgEntriesList, bool>>(this, [this](const std::pair<CAircraftCfgEntriesList, bool> &pair)
@@ -58,26 +125,41 @@ namespace BlackMisc
else if (mode == ModeBlocking)
{
bool ok;
m_parsedCfgEntriesList = parseImpl(m_rootDirectory, m_excludedDirectories, &ok);
emit parsingFinished(ok);
m_parsedCfgEntriesList = performParsing(m_rootDirectory, m_excludedDirectories, &ok);
emit loadingFinished(ok);
}
}
bool CAircraftCfgParser::isLoadingFinished() const
{
return !m_parserWorker || m_parserWorker->isFinished();
}
CAircraftModelList CAircraftCfgParser::getAircraftModels() const
{
return getAircraftCfgEntriesList().toAircraftModelList(this->m_simulatorInfo);
}
void CAircraftCfgParser::updateCfgEntriesList(const CAircraftCfgEntriesList &cfgEntriesList)
{
m_parsedCfgEntriesList = cfgEntriesList;
emit parsingFinished(true);
emit loadingFinished(true);
}
CAircraftCfgEntriesList CAircraftCfgParser::parseImpl(const QString &directory, const QStringList &excludeDirectories, bool *ok)
CAircraftCfgEntriesList CAircraftCfgParser::performParsing(const QString &directory, const QStringList &excludeDirectories, bool *ok)
{
//
// function has to be thread safe
//
*ok = false;
if (m_cancelParsing) { return CAircraftCfgEntriesList(); }
if (m_cancelLoading) { return CAircraftCfgEntriesList(); }
// excluded?
for (const auto &excludeDir : excludeDirectories)
{
if (m_cancelParsing) { return CAircraftCfgEntriesList(); }
if (m_cancelLoading) { return CAircraftCfgEntriesList(); }
if (directory.contains(excludeDir, Qt::CaseInsensitive))
{
CLogMessage(this).debug() << "Skipping directory " << directory;
@@ -101,7 +183,7 @@ namespace BlackMisc
QFileInfoList files = dir.entryInfoList(QDir::Files | QDir::AllDirs | QDir::NoDotAndDotDot, QDir::DirsLast);
for (const auto &file : files)
{
if (m_cancelParsing) { return CAircraftCfgEntriesList(); }
if (m_cancelLoading) { return CAircraftCfgEntriesList(); }
if (file.isDir())
{
QString nextDir = file.absoluteFilePath();
@@ -109,7 +191,7 @@ namespace BlackMisc
if (dir == currentDir) { continue; } // do not recursively call same directory
bool dirOk;
const CAircraftCfgEntriesList subList(parseImpl(nextDir, excludeDirectories, &dirOk));
const CAircraftCfgEntriesList subList(performParsing(nextDir, excludeDirectories, &dirOk));
if (dirOk)
{
result.push_back(subList);
@@ -186,6 +268,10 @@ namespace BlackMisc
{
e.setAtcParkingCode(getFixedIniLineContent(lineFixed));
}
else if (lineFixed.startsWith("atc_airline", Qt::CaseInsensitive))
{
e.setAtcAirline(getFixedIniLineContent(lineFixed));
}
else if (lineFixed.startsWith("description", Qt::CaseInsensitive))
{
e.setDescription(getFixedIniLineContent(lineFixed));
@@ -207,6 +293,14 @@ namespace BlackMisc
{
e.setTexture(getFixedIniLineContent(lineFixed));
}
else if (lineFixed.startsWith("createdBy", Qt::CaseInsensitive))
{
e.setCreatedBy(getFixedIniLineContent(lineFixed));
}
else if (lineFixed.startsWith("sim", Qt::CaseInsensitive))
{
e.setSimName(getFixedIniLineContent(lineFixed));
}
else if (lineFixed.startsWith("title", Qt::CaseInsensitive))
{
e.setTitle(getFixedIniLineContent(lineFixed));

View File

@@ -14,9 +14,11 @@
#include "blackmisc/blackmiscexport.h"
#include "blackmisc/worker.h"
#include "blackmisc/pixmap.h"
#include "blackmisc/simulation/aircraftmodelloader.h"
#include "blackmisc/simulation/fscommon/aircraftcfgentrieslist.h"
#include <atomic>
#include <QPointer>
namespace BlackMisc
{
@@ -25,25 +27,16 @@ namespace BlackMisc
namespace FsCommon
{
//! Utility, parsing the aircraft.cfg files
class BLACKMISC_EXPORT CAircraftCfgParser : public QObject
class BLACKMISC_EXPORT CAircraftCfgParser : public BlackMisc::Simulation::IAircraftModelLoader
{
Q_OBJECT
public:
//! Parser mode
enum ParserMode
{
ModeBlocking,
ModeAsync
};
CAircraftCfgParser() { }
//! Destructor
CAircraftCfgParser();
//! Constructor
CAircraftCfgParser(const QString &rootDirectory, const QStringList &exludes = {}) :
m_rootDirectory(rootDirectory),
m_excludedDirectories(exludes)
{ }
CAircraftCfgParser(const BlackMisc::Simulation::CSimulatorInfo &simInfo, const QString &rootDirectory, const QStringList &exludes = {});
//! Virtual destructor
virtual ~CAircraftCfgParser();
@@ -51,32 +44,31 @@ namespace BlackMisc
//! Change the directory
bool changeRootDirectory(const QString &directory);
//! Parse all cfg files
void parse(ParserMode mode = ModeAsync);
//! Has current directory been parsed?
bool isParsingFinished() const { return m_parserWorker->isFinished(); }
//! Cancel read
void cancelParsing() { m_cancelParsing = true; }
//! Current root directory
QString getRootDirectory() const { return this->m_rootDirectory; }
QString getRootDirectory() const { return this->m_rootDirectory; }
//! Get parsed aircraft cfg entries list
CAircraftCfgEntriesList getAircraftCfgEntriesList() const { return m_parsedCfgEntriesList; }
const CAircraftCfgEntriesList &getAircraftCfgEntriesList() const { return m_parsedCfgEntriesList; }
//! \copydoc IAircraftModelLoader::getPixmapForModel
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;
//! Create an parser object for given simulator
static CAircraftCfgParser *createModelLoader(const BlackMisc::Simulation::CSimulatorInfo &simInfo);
public slots:
//! Parsed or injected entires
void updateCfgEntriesList(const BlackMisc::Simulation::FsCommon::CAircraftCfgEntriesList &cfgEntriesList);
signals:
//! Parsing is finished
void parsingFinished(bool success);
private slots:
CAircraftCfgEntriesList parseImpl(const QString &directory, const QStringList &excludeDirectories, bool *ok);
private:
//! Section within file
enum FileSection
@@ -89,6 +81,10 @@ namespace BlackMisc
//! Does the directory exist?
bool existsDir(const QString &directory = "") const;
//! Perform the parsing
//! \threadsafe
CAircraftCfgEntriesList performParsing(const QString &directory, const QStringList &excludeDirectories, bool *ok);
//! Fix the content read
static QString fixedStringContent(const QVariant &qv);
@@ -98,15 +94,13 @@ namespace BlackMisc
//! Content after "="
static QString getFixedIniLineContent(const QString &line);
QString m_rootDirectory; //!< root directory parsing aircraft.cfg files
QStringList m_excludedDirectories;
CAircraftCfgEntriesList m_parsedCfgEntriesList;
QPointer<BlackMisc::CWorker> m_parserWorker; //!< worker will destroy itself, so weak pointer
std::atomic<bool> m_cancelParsing = { false };
QString m_rootDirectory; //!< root directory parsing aircraft.cfg files
QStringList m_excludedDirectories; //!< directories not to be parsed
CAircraftCfgEntriesList m_parsedCfgEntriesList; //!< parsed entries
QPointer<BlackMisc::CWorker> m_parserWorker; //!< worker will destroy itself, so weak pointer
};
} // namespace
} // namespace
} // namespace
#endif // guard

View File

@@ -20,7 +20,6 @@ namespace BlackMisc
{
namespace FsCommon
{
using FsRegistryPathPair = QList<QPair<QString, QString>>;
QString CFsCommonUtil::fsxDirFromRegistry()
@@ -28,7 +27,6 @@ namespace BlackMisc
QString fsxPath;
if (CProject::isCompiledWithFsxSupport())
{
FsRegistryPathPair fsxRegistryPathPairs =
{
{ QStringLiteral("HKEY_CURRENT_USER\\Software\\Microsoft\\Microsoft Games\\Flight Simulator\\10.0"), QStringLiteral("AppPath") },
@@ -46,6 +44,21 @@ namespace BlackMisc
return fsxPath;
}
QString CFsCommonUtil::fsxDir()
{
QString dir(fsxDirFromRegistry());
if (!dir.isEmpty()) { return dir; }\
//! \todo allow to read a user defined value from settings
return "P:/FlightSimulatorX (MSI)";
}
QString CFsCommonUtil::p3dDir()
{
//! \todo P3D resolution
return fsxDir();
}
QString CFsCommonUtil::fsxSimObjectsDirFromRegistry()
{
QString fsxPath = fsxDirFromRegistry();
@@ -54,6 +67,38 @@ namespace BlackMisc
return fsxPath;
}
QString CFsCommonUtil::fsxSimObjectsDir()
{
QString dir(fsxSimObjectsDirFromRegistry());
if (!dir.isEmpty()) { return dir; }
//! \todo allow to read a user defined value from settings
return "P:/FlightSimulatorX (MSI)/SimObjects"; // "p:/temp/SimObjects"
}
const QStringList &CFsCommonUtil::fsxSimObjectsExcludeDirectories()
{
static const QStringList exclude
{
"SimObjects/Animals",
"SimObjects/Misc",
"SimObjects/GroundVehicles",
"SimObjects/Boats"
};
return exclude;
}
QString CFsCommonUtil::p3dSimObjectsDir()
{
//! \todo P3D resolution
return fsxSimObjectsDir();
}
const QStringList &CFsCommonUtil::p3dSimObjectsExcludeDirectories()
{
return fsxSimObjectsExcludeDirectories();
}
QString CFsCommonUtil::fs9DirFromRegistry()
{
QString fs9Path;
@@ -76,6 +121,15 @@ namespace BlackMisc
return fs9Path;
}
QString CFsCommonUtil::fs9Dir()
{
QString dir(fs9DirFromRegistry());
if (!dir.isEmpty()) { return dir; }
//! \todo hardcoded sim parts should come from settings
return "C:/Flight Simulator 9";
}
QString CFsCommonUtil::fs9AircraftDirFromRegistry()
{
QString fs9Path = fs9DirFromRegistry();
@@ -84,6 +138,20 @@ namespace BlackMisc
return fs9Path;
}
QString CFsCommonUtil::fs9AircraftDir()
{
QString dir(fs9AircraftDirFromRegistry());
if (!dir.isEmpty()) { return dir; }
//! \todo hardcoded sim parts should come from settings
return "C:/Flight Simulator 9/Aircraft";
}
const QStringList &CFsCommonUtil::fs9AircraftObjectsExcludeDirectories()
{
static const QStringList exclude;
return exclude;
}
} // namespace
} // namespace
} // namespace

View File

@@ -25,20 +25,47 @@ namespace BlackMisc
class BLACKMISC_EXPORT CFsCommonUtil
{
public:
CFsCommonUtil();
//! Constructor
CFsCommonUtil() = delete;
//! FSX directory obtained from registry
static QString fsxDirFromRegistry();
//! FSX directory from different sources
static QString fsxDir();
//! P3D directory from different sources
static QString p3dDir();
//! FSX's simObject directory from registry
static QString fsxSimObjectsDirFromRegistry();
//! FSX's sim object dir, resolved from multiple sources
static QString fsxSimObjectsDir();
//! Exclude directories for simObjects
static const QStringList &fsxSimObjectsExcludeDirectories();
//! P3D's sim object dir, resolved from multiple sources
static QString p3dSimObjectsDir();
//! Exclude directories for simObjects
static const QStringList &p3dSimObjectsExcludeDirectories();
//! FS9 directory obtained from registry
static QString fs9DirFromRegistry();
//! FS9 directory obtained from multiple sources
static QString fs9Dir();
//! FS9's aircraft directory from registry
static QString fs9AircraftDirFromRegistry();
//! FS9's aircraft directory
static QString fs9AircraftDir();
//! Exclude directories for aircraft objects
static const QStringList &fs9AircraftObjectsExcludeDirectories();
};
} // namespace

View File

@@ -8,7 +8,6 @@
*/
#include "modelmappingsprovidervpilot.h"
#include "blackmisc/network/aircraftmapping.h"
#include <QtXml/QDomElement>
#include <QFile>
@@ -33,10 +32,10 @@ namespace BlackMisc
bool CModelMappingsProviderVPilot::read()
{
Q_ASSERT_X(this->m_vPilotReader, Q_FUNC_INFO, "missing reader");
bool success = this->m_vPilotReader->read();
bool success = this->m_vPilotReader->read(false);
if (success)
{
this->m_mappings = this->m_vPilotReader->getRules().toMappings();
this->m_datastoreModels = this->m_vPilotReader->getRules().toAircraftModels();
}
return success;
}