refs #361, some own ini reader got lost in master, re-applied changes

This commit is contained in:
Klaus Basan
2015-05-06 02:46:42 +02:00
committed by Mathew Sutcliffe
parent 1c3bb8d463
commit 66075ca0d0
4 changed files with 244 additions and 171 deletions

View File

@@ -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; }

View File

@@ -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<CAircraftCfgEntries>
{
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)

View File

@@ -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<CAircraftCfgEntries> 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<QMetaType::Type>(qv.type()) == QMetaType::QStringList)
{
QStringList l = qv.toStringList();
return l.join(",").trimmed();
}
else if (static_cast<QMetaType::Type>(qv.type()) == QMetaType::QString)
{
return qv.toString().trimmed();
}
Q_ASSERT(false);
return "";
}
/*
* Register metadata
*/
void CAircraftCfgEntriesList::registerMetadata()
{
qRegisterMetaType<BlackMisc::CSequence<CAircraftCfgEntries>>();

View File

@@ -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