refs #452, adjusted aircraft/aviation classes

* support for loading from datastore
* improved timestamp handling
* new color and country classes
* new attributes
* updates for missing parts in CUser
This commit is contained in:
Klaus Basan
2015-09-23 03:20:36 +02:00
committed by Mathew Sutcliffe
parent c5f7179588
commit ae24700299
45 changed files with 2762 additions and 401 deletions

View File

@@ -56,7 +56,6 @@ namespace BlackMisc
clear();
for (const auto &e : json.keys())
{
CAircraftEngine engine;
int number = e.toInt();
engine.convertFromJson(json.value(e).toObject());

View File

@@ -8,11 +8,13 @@
*/
#include "blackmisc/aviation/aircrafticaocode.h"
#include "blackmisc/aviation/airlineicaocode.h"
#include "blackmisc/propertyindex.h"
#include "blackmisc/blackmiscfreefunctions.h"
#include "blackmisc/variant.h"
#include "blackmisc/datastoreutility.h"
#include <tuple>
#include <QThreadStorage>
#include <QRegularExpression>
using namespace BlackMisc;
@@ -25,20 +27,48 @@ namespace BlackMisc
m_designator(designator), m_combinedType(combinedType)
{}
CAircraftIcaoCode::CAircraftIcaoCode(const QString &icao, const QString &combinedType, const QString &manufacturer, const QString &model, const QString &wtc, bool realworld, bool legacy, bool military)
CAircraftIcaoCode::CAircraftIcaoCode(const QString &icao, const QString &combinedType, const QString &manufacturer, const QString &model, const QString &wtc, bool realworld, bool legacy, bool military, int rank)
: m_designator(icao.trimmed().toUpper()), m_combinedType(combinedType.trimmed().toUpper()), m_manufacturer(manufacturer.trimmed()),
m_modelDescription(model.trimmed()), m_wtc(wtc.trimmed().toUpper()), m_realworld(realworld), m_legacy(legacy), m_military(military)
{}
m_modelDescription(model.trimmed()), m_wtc(wtc.trimmed().toUpper()), m_realWorld(realworld), m_legacy(legacy), m_military(military), m_rank(rank)
{
if (m_rank < 0 || m_rank >= 10) { m_rank = 10; }
}
QString CAircraftIcaoCode::convertToQString(bool i18n) const
{
Q_UNUSED(i18n);
QString s(this->m_designator);
if (this->hasCombinedType()) { s.append(" ").append(this->m_combinedType); }
if (this->hasValidCombinedType()) { s.append(" ").append(this->m_combinedType); }
if (this->hasValidWtc()) { s.append(" ").append(this->m_wtc); }
return s;
}
void CAircraftIcaoCode::updateMissingParts(const CAircraftIcaoCode &otherIcaoCode)
{
if (!this->hasDesignator()) { this->setDesignator(otherIcaoCode.getDesignator()); }
if (!this->hasValidWtc()) { this->setWtc(otherIcaoCode.getDesignator()); }
if (!this->hasValidCombinedType()) { this->setCombinedType(otherIcaoCode.getCombinedType()); }
if (this->m_manufacturer.isEmpty()) { this->setManufacturer(otherIcaoCode.getManufacturer());}
if (this->m_modelDescription.isEmpty()) { this->setModelDescription(otherIcaoCode.getModelDescription()); }
if (!this->hasValidDbKey())
{
this->setDbKey(otherIcaoCode.getDbKey());
this->setUtcTimestamp(otherIcaoCode.getUtcTimestamp());
}
}
CStatusMessageList CAircraftIcaoCode::validate() const
{
static const CLogCategoryList cats( { CLogCategory("swift.blackmisc.aircrafticao"), CLogCategory::validation()});
CStatusMessageList msg;
if (!hasKnownDesignator()) { msg.push_back(CStatusMessage(cats, CStatusMessage::SeverityError, "Aircraft ICAO: unknown designator")); }
if (!hasValidCombinedType()) { msg.push_back(CStatusMessage(cats, CStatusMessage::SeverityError, "Aircraft ICAO: invalid combined type")); }
if (!hasValidWtc()) { msg.push_back(CStatusMessage(cats, CStatusMessage::SeverityError, "Aircraft ICAO: wrong WTC")); }
if (!hasManufacturer()) { msg.push_back(CStatusMessage(cats, CStatusMessage::SeverityError, "Aircraft ICAO: missing manufacturer")); }
if (!hasModelDescription()) { msg.push_back(CStatusMessage(cats, CStatusMessage::SeverityError, "Aircraft ICAO: no description")); }
return msg;
}
bool CAircraftIcaoCode::hasDesignator() const
{
return !this->m_designator.isEmpty();
@@ -49,12 +79,54 @@ namespace BlackMisc
return (this->hasDesignator() && this->getDesignator() != "ZZZZ");
}
bool CAircraftIcaoCode::hasValidCombinedType() const
{
return isValidCombinedType(getCombinedType());
}
QString CAircraftIcaoCode::getEngineType() const
{
if (this->m_combinedType.length() != 3) return "";
return this->m_combinedType.right(1);
}
int CAircraftIcaoCode::getEngineCount() const
{
if (this->m_combinedType.length() < 2) { return -1; }
QString c(this->m_combinedType.mid(1, 1));
if (c == "-") { return -1; }
bool ok;
int ec = c.toInt(&ok);
if (ok && ec >= 0 && ec < 10) { return ec; }
return -1;
}
QString CAircraftIcaoCode::getEngineCountString() const
{
if (this->m_combinedType.length() < 2) { return ""; }
return this->m_combinedType.mid(1, 1);
}
QString CAircraftIcaoCode::getAircraftType() const
{
if (this->m_combinedType.length() < 1) { return ""; }
QString c(this->m_combinedType.left(1));
if (c == "-") { return ""; }
return c;
}
QString CAircraftIcaoCode::getDesignatorManufacturer() const
{
QString d(getDesignator());
if (this->hasManufacturer()) { d = d.append(" ").append(this->getManufacturer());}
return d.trimmed();
}
bool CAircraftIcaoCode::hasManufacturer() const
{
return !m_manufacturer.isEmpty();
}
bool CAircraftIcaoCode::isVtol() const
{
// special designators
@@ -79,9 +151,62 @@ namespace BlackMisc
return false;
}
void CAircraftIcaoCode::setCodeFlags(bool military, bool legacy, bool realWorld)
{
m_military = military;
m_legacy = legacy;
m_realWorld = realWorld;
}
void CAircraftIcaoCode::setMilitary(bool military)
{
m_military = military;
}
void CAircraftIcaoCode::setRealWorld(bool realWorld)
{
m_realWorld = realWorld;
}
void CAircraftIcaoCode::setLegacy(bool legacy)
{
m_legacy = legacy;
}
QString CAircraftIcaoCode::getRankString() const
{
return QString::number(getRank());
}
void CAircraftIcaoCode::setRank(int rank)
{
if (rank < 0 || rank >= 10)
{
m_rank = 10;
}
else
{
m_rank = rank;
}
}
QString CAircraftIcaoCode::getCombinedStringWithKey() const
{
QString s(getDesignator());
if (hasManufacturer()) { s = s.append(" ").append(getManufacturer()); }
if (hasModelDescription()) { s = s.append(" ").append(getModelDescription()); }
return s.append(" ").append(getDbKeyAsStringInParentheses());
}
bool CAircraftIcaoCode::hasCompleteData() const
{
return hasCombinedType() && hasDesignator() && hasValidWtc();
return hasValidCombinedType() && hasDesignator() && hasValidWtc() && hasManufacturer();
}
bool CAircraftIcaoCode::matchesDesignator(const QString &designator) const
{
if (designator.isEmpty()) { return false; }
return designator.trimmed().toUpper() == this->m_designator;
}
CVariant CAircraftIcaoCode::propertyByIndex(const BlackMisc::CPropertyIndex &index) const
@@ -108,7 +233,11 @@ namespace BlackMisc
case IndexIsMilitary:
return CVariant::fromValue(this->m_military);
case IndexIsRealworld:
return CVariant::fromValue(this->m_realworld);
return CVariant::fromValue(this->m_realWorld);
case IndexRank:
return CVariant::fromValue(this->m_rank);
case IndexDesignatorManufacturer:
return CVariant::fromValue(this->getDesignatorManufacturer());
default:
return CValueObject::propertyByIndex(index);
}
@@ -142,6 +271,9 @@ namespace BlackMisc
case IndexIsMilitary:
this->m_military = variant.toBool();
break;
case IndexRank:
this->m_rank = variant.toInt();
break;
default:
CValueObject::setPropertyByIndex(variant, index);
break;
@@ -162,50 +294,58 @@ namespace BlackMisc
{
if (combinedType.length() != 3) { return false; }
// Amphibian, Glider, Helicopter, Seaplane, Landplane, Tilt wing
// Electric, Jet, Piston, Turpoprop
static QThreadStorage<QRegularExpression> tsRegex;
if (! tsRegex.hasLocalData()) { tsRegex.setLocalData(QRegularExpression("^[A-Z][0-9][A-Z]$")); }
if (! tsRegex.hasLocalData()) { tsRegex.setLocalData(QRegularExpression("^[AGHSLT][0-9][EJPT]$")); }
const QRegularExpression &regexp = tsRegex.localData();
return (regexp.match(combinedType).hasMatch());
}
CAircraftIcaoCode CAircraftIcaoCode::fromDatabaseJson(const QJsonObject &json)
bool CAircraftIcaoCode::isValidWtc(const QString &candidate)
{
QJsonArray inner = json["cell"].toArray();
Q_ASSERT_X(!inner.isEmpty(), Q_FUNC_INFO, "Missing JSON");
if (inner.isEmpty()) { return CAircraftIcaoCode(); }
if (candidate.isEmpty()) { return true; } // we accept unspecified
if (candidate.length() == 1)
{
return candidate == "L" || candidate == "M" || candidate == "H";
}
return false;
}
int i = 0;
int dbKey(inner.at(i++).toInt(-1));
QString designator(inner.at(i++).toString());
QString manufacturer(inner.at(i++).toString());
QString model(inner.at(i++).toString());
QString type(inner.at(i++).toString());
QString engine(inner.at(i++).toString());
QString engineCount(inner.at(i++).toString());
CAircraftIcaoCode CAircraftIcaoCode::fromDatabaseJson(const QJsonObject &json, const QString &prefix)
{
if (!existsKey(json, prefix))
{
// when using relationship, this can be null
return CAircraftIcaoCode();
}
QString designator(json.value(prefix + "designator").toString());
QString manufacturer(json.value(prefix + "manufacturer").toString());
QString model(json.value(prefix + "model").toString());
QString type(json.value(prefix + "type").toString());
QString engine(json.value(prefix + "engine").toString());
int engineCount(json.value(prefix + "enginecount").toInt(-1));
QString combined(createdCombinedString(type, engineCount, engine));
QString wtc(inner.at(i++).toString());
QString wtc(json.value("wtc").toString());
if (wtc.length() > 1 && wtc.contains("/"))
{
// "L/M" -> "M"
wtc = wtc.right(1);
}
bool real = CDatastoreUtility::dbBoolStringToBool(inner.at(i++).toString());
bool legacy = CDatastoreUtility::dbBoolStringToBool(inner.at(i++).toString());
bool military = CDatastoreUtility::dbBoolStringToBool(inner.at(i++).toString());
bool real = CDatastoreUtility::dbBoolStringToBool(json.value(prefix + "realworld").toString());
bool legacy = CDatastoreUtility::dbBoolStringToBool(json.value(prefix + "legacy").toString());
bool military = CDatastoreUtility::dbBoolStringToBool(json.value(prefix + "military").toString());
int rank(json.value("rank").toInt(10));
Q_ASSERT_X(wtc.length() < 2, Q_FUNC_INFO, "WTC too long");
CAircraftIcaoCode code(
designator,
combined,
manufacturer,
model,
wtc,
real,
legacy,
military
designator, combined,
manufacturer, model, wtc,
real, legacy, military, rank
);
code.setDbKey(dbKey);
code.setKeyAndTimestampFromDatabaseJson(json, prefix);
return code;
}
@@ -235,5 +375,16 @@ namespace BlackMisc
return c;
}
QString CAircraftIcaoCode::createdCombinedString(const QString &type, int engineCount, const QString &engine)
{
if (engineCount >= 0 && engineCount < 10)
{
return createdCombinedString(type, QString::number(engineCount), engine);
}
else
{
return createdCombinedString(type, "", engine);
}
}
} // namespace
} // namespace

View File

@@ -17,11 +17,14 @@
#include "blackmisc/propertyindex.h"
#include "blackmisc/blackmiscfreefunctions.h"
#include "blackmisc/datastore.h"
#include "blackmisc/statusmessagelist.h"
namespace BlackMisc
{
namespace Aviation
{
class CAirlineIcaoCode;
//! Value object for ICAO classification
class BLACKMISC_EXPORT CAircraftIcaoCode :
public CValueObject<CAircraftIcaoCode>,
@@ -40,6 +43,8 @@ namespace BlackMisc
IndexIsMilitary,
IndexIsLegacy,
IndexIsVtol,
IndexRank,
IndexDesignatorManufacturer
};
//! Default constructor.
@@ -50,7 +55,7 @@ namespace BlackMisc
//! Constructor
CAircraftIcaoCode(const QString &icao, const QString &combinedType, const QString &manufacturer,
const QString &model, const QString &wtc, bool realworld, bool legacy, bool military);
const QString &model, const QString &wtc, bool realworld, bool legacy, bool military, int rank);
//! Get ICAO designator, e.g. "B737"
const QString &getDesignator() const { return m_designator; }
@@ -68,26 +73,44 @@ namespace BlackMisc
const QString &getCombinedType() const { return this->m_combinedType; }
//! Combined type available?
bool hasCombinedType() const { return this->getCombinedType().length() == 3; }
bool hasValidCombinedType() const;
//! Get engine type, e.g. "J"
QString getEngineType() const;
//! Engine count if any, -1 if no value is set
int getEngineCount() const;
//! Engine count as string, if not available ""
QString getEngineCountString() const;
//! Aircraft type, such a L(andplane), S(eaplane), H(elicopter)
QString getAircraftType() const;
//! Set type
void setCombinedType(const QString &type) { this->m_combinedType = type.trimmed().toUpper(); }
//! Get model description, e.g. "A-330-200"
const QString &getModelDescription() const { return m_modelDescription; }
//! Designator + Manufacturer
QString getDesignatorManufacturer() const;
//! Set the model description
void setModelDescription(const QString &modelDescription) { m_modelDescription = modelDescription.trimmed(); }
//! Has model description
bool hasModelDescription() const { return !this->m_modelDescription.isEmpty(); }
//! Get manufacturer, e.g. "Airbus"
const QString &getManufacturer() const { return m_manufacturer; }
//! Set the manufacturer
void setManufacturer(const QString &manufacturer) { m_manufacturer = manufacturer.trimmed(); }
//! Manufacturer
bool hasManufacturer() const;
//! Get WTC
const QString &getWtc() const { return m_wtc; }
@@ -100,9 +123,45 @@ namespace BlackMisc
//! Is VTOL aircraft (helicopter, tilt wing)
bool isVtol() const;
//! Military?
bool isMilitary() const { return m_military; }
//! Real world aircraft?
bool isRealWorld() const { return m_realWorld; }
//! Legacy aircraft
bool isLegacyAircraft() const { return m_legacy; }
//! Flags
void setCodeFlags(bool military, bool legacy, bool realWorld);
//! Military
void setMilitary(bool military);
//! Real world
void setRealWorld(bool realWorld);
//! Legacy
void setLegacy(bool legacy);
//! Ranking
int getRank() const { return m_rank; }
//! Ranking
QString getRankString() const;
//! Ranking
void setRank(int rank);
//! Comined descriptive string with key
QString getCombinedStringWithKey() const;
//! All data set?
bool hasCompleteData() const;
//! Matches designator string?
bool matchesDesignator(const QString &designator) const;
//! \copydoc CValueObject::propertyByIndex
CVariant propertyByIndex(const BlackMisc::CPropertyIndex &index) const;
@@ -112,14 +171,23 @@ namespace BlackMisc
//! \copydoc CValueObject::convertToQString
QString convertToQString(bool i18n = false) const;
//! Update missing parts
void updateMissingParts(const CAircraftIcaoCode &otherIcaoCode);
//! Validate data
BlackMisc::CStatusMessageList validate() const;
//! Valid designator?
static bool isValidDesignator(const QString &designator);
//! Valid combined type
static bool isValidCombinedType(const QString &combinedType);
//! Valid WTC code?
static bool isValidWtc(const QString &candidate);
//! From our database JSON format
static CAircraftIcaoCode fromDatabaseJson(const QJsonObject &json);
static CAircraftIcaoCode fromDatabaseJson(const QJsonObject &json, const QString &prefix = QString());
private:
BLACK_ENABLE_TUPLE_CONVERSION(CAircraftIcaoCode)
@@ -127,14 +195,17 @@ namespace BlackMisc
QString m_combinedType; //!< "L2J"
QString m_manufacturer; //!< "Airbus"
QString m_modelDescription; //!< "A-330-200"
QString m_wtc; //!< wake turbulence "M","H" "L/M", "L"
bool m_realworld = true; //!< real world aircraft
QString m_wtc; //!< wake turbulence "M","H" "L/M", "L", we only use the one letter versions
bool m_realWorld = true; //!< real world aircraft
bool m_legacy = false; //!< legacy code
bool m_military = false; //!< military aircraft?
int m_rank = 10; //!< rank among same codes
//! Create a combined string like L2J
static QString createdCombinedString(const QString &type, const QString &engineCount, const QString &engine);
//! Create a combined string like L2J
static QString createdCombinedString(const QString &type, int engineCount, const QString &engine);
};
} // namespace
} // namespace
@@ -142,14 +213,16 @@ namespace BlackMisc
Q_DECLARE_METATYPE(BlackMisc::Aviation::CAircraftIcaoCode)
BLACK_DECLARE_TUPLE_CONVERSION(BlackMisc::Aviation::CAircraftIcaoCode, (
o.m_dbKey,
o.m_timestampMSecsSinceEpoch,
o.m_designator,
o.m_combinedType,
o.m_manufacturer,
o.m_modelDescription,
o.m_wtc,
o.m_military,
o.m_realworld,
o.m_legacy
o.m_realWorld,
o.m_legacy,
o.m_rank
))
#endif // guard

View File

@@ -18,6 +18,58 @@ namespace BlackMisc
CSequence<CAircraftIcaoCode>(other)
{ }
CAircraftIcaoCodeList CAircraftIcaoCodeList::findByDesignator(const QString &designator)
{
if (!CAircraftIcaoCode::isValidDesignator(designator)) { return CAircraftIcaoCodeList(); }
return this->findBy([&](const CAircraftIcaoCode & code)
{
return code.matchesDesignator(designator);
});
}
CAircraftIcaoCodeList CAircraftIcaoCodeList::findByManufacturer(const QString &manufacturer)
{
if (manufacturer.isEmpty()) { return CAircraftIcaoCodeList(); }
return this->findBy([&](const CAircraftIcaoCode & code)
{
return code.getManufacturer().startsWith(manufacturer, Qt::CaseInsensitive);
});
}
CAircraftIcaoCodeList CAircraftIcaoCodeList::findByDescription(const QString &description)
{
if (description.isEmpty()) { return CAircraftIcaoCodeList(); }
return this->findBy([&](const CAircraftIcaoCode & code)
{
return code.getModelDescription().startsWith(description, Qt::CaseInsensitive);
});
}
CAircraftIcaoCode CAircraftIcaoCodeList::findFirstByDesignatorAndRank(const QString &designator)
{
if (!CAircraftIcaoCode::isValidDesignator(designator)) { return CAircraftIcaoCode(); }
CAircraftIcaoCodeList codes(findByDesignator(designator));
if (codes.isEmpty()) { return CAircraftIcaoCode(); }
if (codes.size() < 2) { return codes.front(); }
codes.sortBy(&CAircraftIcaoCode::getRank, &CAircraftIcaoCode::getDbKey);
return codes.front();
}
void CAircraftIcaoCodeList::sortByRank()
{
this->sortBy(&CAircraftIcaoCode::getRank);
}
QStringList CAircraftIcaoCodeList::toCompleterStrings() const
{
QStringList c;
for (const CAircraftIcaoCode &icao : *this)
{
c.append(icao.getCombinedStringWithKey());
}
return c;
}
CAircraftIcaoCodeList CAircraftIcaoCodeList::fromDatabaseJson(const QJsonArray &array, bool ignoreIncomplete)
{
CAircraftIcaoCodeList codes;

View File

@@ -14,6 +14,7 @@
#include "aircrafticaocode.h"
#include "blackmisc/blackmiscexport.h"
#include "blackmisc/datastoreobjectlist.h"
#include "blackmisc/collection.h"
#include "blackmisc/sequence.h"
#include <initializer_list>
@@ -25,6 +26,7 @@ namespace BlackMisc
//! Value object encapsulating a list of ICAO codes.
class BLACKMISC_EXPORT CAircraftIcaoCodeList :
public CSequence<CAircraftIcaoCode>,
public BlackMisc::IDatastoreObjectListWithIntegerKey<CAircraftIcaoCode, CAircraftIcaoCodeList>,
public BlackMisc::Mixin::MetaType<CAircraftIcaoCodeList>
{
public:
@@ -36,6 +38,24 @@ namespace BlackMisc
//! Construct from a base class object.
CAircraftIcaoCodeList(const CSequence<CAircraftIcaoCode> &other);
//! Find by designator
CAircraftIcaoCodeList findByDesignator(const QString &designator);
//! Find by manufacturer
CAircraftIcaoCodeList findByManufacturer(const QString &manufacturer);
//! Find by model description
CAircraftIcaoCodeList findByDescription(const QString &description);
//! Find by designator, then best match by rank
CAircraftIcaoCode findFirstByDesignatorAndRank(const QString &designator);
//! Sort by rank
void sortByRank();
//! For selection completion
QStringList toCompleterStrings() const;
//! From our database JSON format
static CAircraftIcaoCodeList fromDatabaseJson(const QJsonArray &array, bool ignoreIncomplete = true);
};

View File

@@ -41,7 +41,7 @@ namespace BlackMisc
s.append(" pitch: ").append(this->m_pitch.toQString(i18n));
s.append(" gs: ").append(this->m_groundspeed.toQString(i18n));
s.append(" heading: ").append(this->m_heading.toQString(i18n));
s.append(" timestamp: ").append(this->getFormattedUtcTimestamp());
s.append(" timestamp: ").append(this->getFormattedUtcTimestampDhms());
return s;
}

View File

@@ -14,8 +14,8 @@
#include "blackmisc/blackmiscexport.h"
#include "blackmisc/aviation/aircraftsituation.h"
#include "blackmisc/timestampobjectlist.h"
#include "blackmisc/aviation/callsignobjectlist.h"
#include "blackmisc/timestampobjectlist.h"
#include "blackmisc/sequence.h"
namespace BlackMisc

View File

@@ -13,8 +13,9 @@
#include "blackmisc/variant.h"
#include <tuple>
#include <QThreadStorage>
#include <QRegularExpression>
#include "blackmisc/logmessage.h"
using namespace BlackMisc;
@@ -22,13 +23,12 @@ namespace BlackMisc
{
namespace Aviation
{
CAirlineIcaoCode::CAirlineIcaoCode(const QString &airlineDesignator)
: m_designator(airlineDesignator.trimmed().toUpper())
{}
CAirlineIcaoCode::CAirlineIcaoCode(const QString &airlineDesignator, const QString &airlineName, const QString &countryIso, const QString &country, const QString &telephony, bool virtualAirline)
: m_designator(airlineDesignator.trimmed().toUpper()), m_name(airlineName), m_countryIso(countryIso.trimmed().toUpper()), m_country(country), m_telephonyDesignator(telephony), m_isVa(virtualAirline)
CAirlineIcaoCode::CAirlineIcaoCode(const QString &airlineDesignator, const QString &airlineName, const BlackMisc::CCountry &country, const QString &telephony, bool virtualAirline, bool operating)
: m_designator(airlineDesignator.trimmed().toUpper()), m_name(airlineName), m_country(country), m_telephonyDesignator(telephony), m_isVa(virtualAirline), m_isOperating(operating)
{}
const QString CAirlineIcaoCode::getVDesignator() const
@@ -37,15 +37,60 @@ namespace BlackMisc
return QString("V").append(this->m_designator);
}
QString CAirlineIcaoCode::getDesignatorNameCountry() const
{
QString s(this->getDesignator());
if (this->hasName()) { s = s.append(" ").append(this->getName()); }
if (this->hasValidCountry()) { s = s.append(" ").append(this->getCountryIso()); }
return s.trimmed();
}
bool CAirlineIcaoCode::hasValidCountry() const
{
return this->m_country.isValid();
}
bool CAirlineIcaoCode::hasValidDesignator() const
{
return isValidAirlineDesignator(m_designator);
}
bool CAirlineIcaoCode::matchesDesignator(const QString &designator) const
{
if (designator.isEmpty()) { return false; }
return designator.trimmed().toUpper() == this->m_designator;
}
bool CAirlineIcaoCode::matchesVDesignator(const QString &designator) const
{
if (designator.isEmpty()) { return false; }
return designator.trimmed().toUpper() == this->getVDesignator();
}
bool CAirlineIcaoCode::hasCompleteData() const
{
return this->hasDesignator() && this->hasCountryIso() && this->hasName();
return this->hasValidDesignator() && this->hasValidCountry() && this->hasName();
}
CIcon CAirlineIcaoCode::toIcon() const
{
if (this->m_designator.length() > 2)
{
return CIcon("images/airlines/" + m_designator.toLower() + ".png",
this->convertToQString());
}
else
{
return CIcon::iconByIndex(CIcons::StandardIconEmpty);
}
}
QString CAirlineIcaoCode::convertToQString(bool i18n) const
{
Q_UNUSED(i18n);
QString s(this->m_designator);
if (this->m_name.isEmpty()) { return ""; }
if (!this->m_name.isEmpty()) { s.append(" (").append(this->m_name).append(")"); }
return s;
}
@@ -59,15 +104,19 @@ namespace BlackMisc
case IndexAirlineDesignator:
return CVariant::fromValue(this->m_designator);
case IndexAirlineCountryIso:
return CVariant::fromValue(this->m_countryIso);
return CVariant::fromValue(this->getCountryIso());
case IndexAirlineCountry:
return CVariant::fromValue(this->m_country);
return this->m_country.propertyByIndex(index.copyFrontRemoved());
case IndexAirlineName:
return CVariant::fromValue(this->m_name);
case IndexTelephonyDesignator:
return CVariant::fromValue(this->m_telephonyDesignator);
case IndexIsVirtualAirline:
return CVariant::fromValue(this->m_isVa);
case IndexIsOperating:
return CVariant::fromValue(this->m_isOperating);
case IndexDesignatorNameCountry:
return CVariant::fromValue(this->getDesignatorNameCountry());
default:
return CValueObject::propertyByIndex(index);
}
@@ -83,11 +132,8 @@ namespace BlackMisc
case IndexAirlineDesignator:
this->setDesignator(variant.value<QString>());
break;
case IndexAirlineCountryIso:
this->setCountryIso(variant.value<QString>());
break;
case IndexAirlineCountry:
this->setCountry(variant.value<QString>());
this->setCountry(variant.value<CCountry>());
break;
case IndexAirlineName:
this->setName(variant.value<QString>());
@@ -98,12 +144,25 @@ namespace BlackMisc
case IndexIsVirtualAirline:
this->setVirtualAirline(variant.toBool());
break;
case IndexIsOperating:
this->setOperating(variant.toBool());
break;
default:
CValueObject::setPropertyByIndex(variant, index);
break;
}
}
CStatusMessageList CAirlineIcaoCode::validate() const
{
static const CLogCategoryList cats( { CLogCategory(this->getClassName()), CLogCategory::validation()});
CStatusMessageList msgs;
if (!hasValidDesignator()) { msgs.push_back(CStatusMessage(cats, CStatusMessage::SeverityError, "Airline: missing designator")); }
if (!hasValidCountry()) { msgs.push_back(CStatusMessage(cats, CStatusMessage::SeverityError, "Airline: missing country")); }
if (!hasName()) { msgs.push_back(CStatusMessage(cats, CStatusMessage::SeverityError, "Airline: no name")); }
return msgs;
}
bool CAirlineIcaoCode::isValidAirlineDesignator(const QString &airline)
{
if (airline.length() < 2 || airline.length() > 5) return false;
@@ -114,27 +173,47 @@ namespace BlackMisc
return (regexp.match(airline).hasMatch());
}
CAirlineIcaoCode CAirlineIcaoCode::fromDatabaseJson(const QJsonObject &json)
QString CAirlineIcaoCode::getCombinedStringWithKey() const
{
// https://ubuntu12/vatrep/public/service/allairlineicao.php?rows=10
QJsonArray inner = json["cell"].toArray();
Q_ASSERT_X(!inner.isEmpty(), Q_FUNC_INFO, "Missing JSON");
if (inner.isEmpty()) { return CAirlineIcaoCode(); }
QString s(getVDesignator());
if (hasName()) { s = s.append(" ").append(getName()); }
return s.append(" ").append(getDbKeyAsStringInParentheses());
}
int i = 0;
int dbKey = inner.at(i++).toInt(-1);
QString designator(inner.at(i++).toString());
QString vDesignator(inner.at(i++).toString());
Q_UNUSED(vDesignator);
QString telephony(inner.at(i++).toString());
QString name(inner.at(i++).toString());
QString countryIso(inner.at(i++).toString());
QString country(inner.at(i++).toString());
bool va = inner.at(i++).toString().startsWith("Y", Qt::CaseInsensitive); // VA
void CAirlineIcaoCode::updateMissingParts(const CAirlineIcaoCode &otherIcaoCode)
{
if (!this->hasValidDesignator()) { this->setDesignator(otherIcaoCode.getDesignator()); }
if (!this->hasValidCountry()) { this->setCountry(otherIcaoCode.getCountry()); }
if (!this->hasName()) { this->setName(otherIcaoCode.getName()); }
if (!this->hasTelephonyDesignator()) { this->setTelephonyDesignator(otherIcaoCode.getTelephonyDesignator()); }
if (!this->hasValidDbKey())
{
this->setDbKey(otherIcaoCode.getDbKey());
this->setUtcTimestamp(otherIcaoCode.getUtcTimestamp());
}
}
CAirlineIcaoCode CAirlineIcaoCode::fromDatabaseJson(const QJsonObject &json, const QString &prefix)
{
if (!existsKey(json, prefix))
{
// when using relationship, this can be null
return CAirlineIcaoCode();
}
QString designator(json.value(prefix + "designator").toString());
QString telephony(json.value(prefix + "callsign").toString());
QString name(json.value(prefix + "name").toString());
QString countryIso(json.value(prefix + "country").toString());
QString countryName(json.value(prefix + "countryname").toString());
bool va = json.value(prefix + "va").toString().startsWith("Y", Qt::CaseInsensitive); // VA
bool operating = json.value(prefix + "operating").toString().startsWith("Y", Qt::CaseInsensitive); // operating
CAirlineIcaoCode code(
designator, name, countryIso, country, telephony, va
designator, name,
CCountry(countryIso, countryName),
telephony, va, operating
);
code.setDbKey(dbKey);
code.setKeyAndTimestampFromDatabaseJson(json, prefix);
return code;
}

View File

@@ -13,9 +13,11 @@
#define BLACKMISC_AVIATION_AIRLINEICAOCODE_H
#include "blackmisc/blackmiscexport.h"
#include "blackmisc/country.h"
#include "blackmisc/datastore.h"
#include "blackmisc/valueobject.h"
#include "blackmisc/propertyindex.h"
#include "blackmisc/statusmessagelist.h"
#include "blackmisc/blackmiscfreefunctions.h"
namespace BlackMisc
@@ -36,7 +38,9 @@ namespace BlackMisc
IndexAirlineCountryIso,
IndexAirlineCountry,
IndexTelephonyDesignator,
IndexIsVirtualAirline
IndexIsVirtualAirline,
IndexIsOperating,
IndexDesignatorNameCountry,
};
//! Default constructor.
@@ -46,7 +50,7 @@ namespace BlackMisc
CAirlineIcaoCode(const QString &airlineDesignator);
//! Constructor.
CAirlineIcaoCode(const QString &airlineDesignator, const QString &airlineName, const QString &countryIso, const QString &country, const QString &telephony, bool virtualAirline);
CAirlineIcaoCode(const QString &airlineDesignator, const QString &airlineName, const BlackMisc::CCountry &country, const QString &telephony, bool virtualAirline, bool operating);
//! Get airline, e.g. "DLH"
const QString &getDesignator() const { return this->m_designator; }
@@ -58,16 +62,16 @@ namespace BlackMisc
void setDesignator(const QString &icaoDesignator) { this->m_designator = icaoDesignator.trimmed().toUpper(); }
//! Get country, e.g. "FR"
const QString &getCountryIso() const { return this->m_countryIso; }
const QString &getCountryIso() const { return this->m_country.getIsoCode(); }
//! Get country, e.g. "FRANCE"
const QString &getCountry() const { return this->m_country; }
const BlackMisc::CCountry &getCountry() const { return this->m_country; }
//! Set country ISO
void setCountryIso(const QString &country) { this->m_countryIso = country.trimmed().toUpper(); }
//! Combined string designator, name, country
QString getDesignatorNameCountry() const;
//! Set country
void setCountry(const QString &country) { this->m_country = country.trimmed(); }
void setCountry(const BlackMisc::CCountry &country) { this->m_country = country; }
//! Get name, e.g. "Lufthansa"
const QString &getName() const { return this->m_name; }
@@ -87,11 +91,23 @@ namespace BlackMisc
//! Virtual airline
void setVirtualAirline(bool va) { m_isVa = va; }
//! Country?
bool hasCountryIso() const { return !this->m_countryIso.isEmpty(); }
//! Operating?
bool isOperating() const { return m_isOperating; }
//! Airline available?
bool hasDesignator() const { return !this->m_designator.isEmpty(); }
//! Operating airline?
void setOperating(bool operating) { m_isOperating = operating; }
//! Country?
bool hasValidCountry() const;
//! Airline designator available?
bool hasValidDesignator() const;
//! Matches designator string?
bool matchesDesignator(const QString &designator) const;
//! Matches v-designator string?
bool matchesVDesignator(const QString &designator) const;
//! Telephony designator?
bool hasTelephonyDesignator() const { return !this->m_telephonyDesignator.isEmpty(); }
@@ -102,6 +118,12 @@ namespace BlackMisc
//! Complete data
bool hasCompleteData() const;
//! Comined string with key
QString getCombinedStringWithKey() const;
//! \copydoc CValueObject::toIcon
CIcon toIcon() const;
//! \copydoc CValueObject::convertToQString
QString convertToQString(bool i18n = false) const;
@@ -111,20 +133,26 @@ namespace BlackMisc
//! \copydoc CValueObject::setPropertyByIndex
void setPropertyByIndex(const CVariant &variant, const BlackMisc::CPropertyIndex &index);
//! Validate data
BlackMisc::CStatusMessageList validate() const;
//! Update missing parts
void updateMissingParts(const CAirlineIcaoCode &otherIcaoCode);
//! Valid designator?
static bool isValidAirlineDesignator(const QString &airline);
//! From our DB JSON
static CAirlineIcaoCode fromDatabaseJson(const QJsonObject &json);
static CAirlineIcaoCode fromDatabaseJson(const QJsonObject &json, const QString &prefix = QString());
private:
BLACK_ENABLE_TUPLE_CONVERSION(CAirlineIcaoCode)
QString m_designator; //!< "DLH"
QString m_name; //!< "Lufthansa"
QString m_countryIso; //!< "FR"
QString m_country; //!< clear text, "Germany"
BlackMisc::CCountry m_country; //!< Country
QString m_telephonyDesignator; //!< "Speedbird"
bool m_isVa = false;
bool m_isVa = false; //!< virtual airline
bool m_isOperating = true; //!< still operating?
};
} // namespace
} // namespace
@@ -132,12 +160,13 @@ namespace BlackMisc
Q_DECLARE_METATYPE(BlackMisc::Aviation::CAirlineIcaoCode)
BLACK_DECLARE_TUPLE_CONVERSION(BlackMisc::Aviation::CAirlineIcaoCode, (
o.m_dbKey,
o.m_timestampMSecsSinceEpoch,
o.m_designator,
o.m_name,
o.m_countryIso,
o.m_country,
o.m_telephonyDesignator,
o.m_isVa
o.m_isVa,
o.m_isOperating
))
#endif // guard

View File

@@ -17,6 +17,24 @@ namespace BlackMisc
CSequence<CAirlineIcaoCode>(other)
{ }
CAirlineIcaoCodeList CAirlineIcaoCodeList::findByDesignator(const QString &designator)
{
if (CAirlineIcaoCode::isValidAirlineDesignator(designator)) { return CAirlineIcaoCodeList(); }
return this->findBy([&](const CAirlineIcaoCode & code)
{
return code.matchesDesignator(designator);
});
}
CAirlineIcaoCode CAirlineIcaoCodeList::findByVDesignator(const QString &designator)
{
if (CAirlineIcaoCode::isValidAirlineDesignator(designator)) { return CAirlineIcaoCode(); }
return this->findFirstBy([&](const CAirlineIcaoCode & code)
{
return code.matchesVDesignator(designator);
});
}
CAirlineIcaoCodeList CAirlineIcaoCodeList::fromDatabaseJson(const QJsonArray &array, bool ignoreIncomplete)
{
CAirlineIcaoCodeList codes;
@@ -28,5 +46,17 @@ namespace BlackMisc
}
return codes;
}
QStringList CAirlineIcaoCodeList::toCompleterStrings() const
{
QStringList c;
for (const CAirlineIcaoCode &icao : *this)
{
QString cs(icao.getCombinedStringWithKey());
c.append(cs);
}
return c;
}
} // namespace
} // namespace

View File

@@ -14,6 +14,7 @@
#include "airlineicaocode.h"
#include "blackmisc/blackmiscexport.h"
#include "blackmisc/datastoreobjectlist.h"
#include "blackmisc/collection.h"
#include "blackmisc/sequence.h"
#include <initializer_list>
@@ -25,6 +26,8 @@ namespace BlackMisc
//! Value object encapsulating a list of ICAO codes.
class BLACKMISC_EXPORT CAirlineIcaoCodeList :
public CSequence<CAirlineIcaoCode>,
public BlackMisc::IDatastoreObjectListWithIntegerKey<CAirlineIcaoCode, CAirlineIcaoCodeList>,
public BlackMisc::Mixin::MetaType<CAirlineIcaoCodeList>
{
public:
@@ -36,6 +39,16 @@ namespace BlackMisc
//! Construct from a base class object.
CAirlineIcaoCodeList(const CSequence<CAirlineIcaoCode> &other);
//! Find by designator
//! Not unique because of virtual airlines
CAirlineIcaoCodeList findByDesignator(const QString &designator);
//! Find by v-designator, this should be unique
CAirlineIcaoCode findByVDesignator(const QString &designator);
//! String list for completion
QStringList toCompleterStrings() const;
//! From our DB JSON
static CAirlineIcaoCodeList fromDatabaseJson(const QJsonArray &array, bool ignoreIncomplete = true);
};

View File

@@ -62,8 +62,8 @@ namespace BlackMisc
} // namespace
BLACK_DECLARE_TUPLE_CONVERSION(BlackMisc::Aviation::CAirportIcaoCode, (
attr(o.m_icaoCode, flags<CaseInsensitiveComparison>())
))
attr(o.m_icaoCode, flags<CaseInsensitiveComparison>())
))
Q_DECLARE_METATYPE(BlackMisc::Aviation::CAirportIcaoCode)
#endif // guard

View File

@@ -241,17 +241,17 @@ namespace BlackMisc
private:
BLACK_ENABLE_TUPLE_CONVERSION(CAtcStation)
CCallsign m_callsign;
BlackMisc::Network::CUser m_controller;
CCallsign m_callsign;
BlackMisc::Network::CUser m_controller;
BlackMisc::PhysicalQuantities::CFrequency m_frequency;
BlackMisc::Geo::CCoordinateGeodetic m_position;
BlackMisc::PhysicalQuantities::CLength m_range;
bool m_isOnline = false;
QDateTime m_bookedFromUtc;
QDateTime m_bookedUntilUtc;
BlackMisc::Geo::CCoordinateGeodetic m_position;
BlackMisc::PhysicalQuantities::CLength m_range;
bool m_isOnline = false;
QDateTime m_bookedFromUtc;
QDateTime m_bookedUntilUtc;
CInformationMessage m_atis { CInformationMessage::ATIS };
CInformationMessage m_metar { CInformationMessage::METAR };
BlackMisc::Audio::CVoiceRoom m_voiceRoom;
BlackMisc::Audio::CVoiceRoom m_voiceRoom;
};
} // namespace
} // namespace

View File

@@ -28,7 +28,6 @@
#include "blackmisc/aviation/atcstationlist.h"
#include "blackmisc/aviation/aircrafticaocode.h"
#include "blackmisc/aviation/aircrafticaocodelist.h"
#include "blackmisc/aviation/aircraftlist.h"
#include "blackmisc/aviation/aircraftsituation.h"
#include "blackmisc/aviation/aircraftsituationlist.h"
#include "blackmisc/aviation/airlineicaocode.h"

View File

@@ -25,24 +25,65 @@ namespace BlackMisc
CLivery::CLivery()
{ }
CLivery::CLivery(const QString &combinedCode, const CAirlineIcaoCode &airline, const QString &description) :
CLivery(-1, combinedCode, airline, description, "", "", false)
{ }
CLivery::CLivery(const QString &combinedCode, const CAirlineIcaoCode &airline, const QString &description, const QString &colorFuselage, const QString &colorTail, bool isMilitary) :
CLivery(-1, combinedCode, airline, description, colorFuselage, colorTail, isMilitary)
{ }
CLivery::CLivery(const QString &combinedCode, const CAirlineIcaoCode &airline, const QString &description, const CRgbColor &colorFuselage, const CRgbColor &colorTail, bool isMilitary) :
CLivery(-1, combinedCode, airline, description, colorFuselage, colorTail, isMilitary)
{ }
CLivery::CLivery(int dbKey, const QString &combinedCode, const CAirlineIcaoCode &airline, const QString &description, const QString &colorFuselage, const QString &colorTail, bool isMilitary) :
m_dbKey(dbKey), m_airline(airline),
IDatastoreObjectWithIntegerKey(dbKey),
m_airline(airline),
m_combinedCode(combinedCode.trimmed().toUpper()), m_description(description.trimmed()),
m_colorFuselage(normalizeHexColor(colorFuselage)), m_colorTail(normalizeHexColor(colorTail)),
m_colorFuselage(CRgbColor(colorFuselage)), m_colorTail(CRgbColor(colorTail)),
m_military(isMilitary)
{ }
CLivery::CLivery(int dbKey, const QString &combinedCode, const CAirlineIcaoCode &airline, const QString &description, const CRgbColor &colorFuselage, const CRgbColor &colorTail, bool isMilitary) :
IDatastoreObjectWithIntegerKey(dbKey),
m_airline(airline),
m_combinedCode(combinedCode.trimmed().toUpper()), m_description(description.trimmed()),
m_colorFuselage(colorFuselage), m_colorTail(colorTail),
m_military(isMilitary)
{ }
bool CLivery::setAirlineIcaoCode(const CAirlineIcaoCode &airlineIcao)
{
if (m_airline == airlineIcao) { return false; }
m_airline = airlineIcao;
return true;
}
bool CLivery::hasColorFuselage() const
{
return m_colorFuselage.isValid();
}
bool CLivery::hasColorTail() const
{
return m_colorTail.isValid();
}
bool CLivery::matchesCombinedCode(const QString &candidate) const
{
if (candidate.isEmpty() || !this->hasCombinedCode()) { return false; }
QString c(candidate.trimmed().toUpper());
return c == this->m_combinedCode;
}
QString CLivery::convertToQString(bool i18n) const
{
QString s(i18n ? QCoreApplication::translate("Aviation", "Livery") : "Livery");
s.append(m_combinedCode);
if (!this->m_description.isEmpty()) { s.append(' ').append(this->m_description); }
if (!this->m_colorFuselage.isEmpty()) { s.append(" F: ").append(this->m_colorFuselage); }
if (!this->m_colorTail.isEmpty()) { s.append(" T: ").append(this->m_colorTail); }
if (this->m_colorFuselage.isValid()) { s.append(" F: ").append(this->m_colorFuselage.hex()); }
if (this->m_colorTail.isValid()) { s.append(" T: ").append(this->m_colorTail.hex()); }
if (this->isMilitary()) { s.append(" Military");}
return s;
@@ -55,38 +96,81 @@ namespace BlackMisc
return !m_description.isEmpty() && !m_combinedCode.isEmpty();
}
CLivery CLivery::fromDatabaseJson(const QJsonObject &json)
CStatusMessageList CLivery::validate() const
{
QJsonArray inner = json["cell"].toArray();
Q_ASSERT_X(!inner.isEmpty(), Q_FUNC_INFO, "Missing JSON");
if (inner.isEmpty()) { return CLivery(); }
static const CLogCategoryList cats( { CLogCategory(this->getClassName()), CLogCategory::validation()});
CStatusMessageList msg;
if (!hasCombinedCode()) { msg.push_back(CStatusMessage(cats, CStatusMessage::SeverityError, "Livery: missing livery code")); }
if (!hasColorFuselage()) { msg.push_back(CStatusMessage(cats, CStatusMessage::SeverityWarning, "Livery: no fuselage color")); }
if (!hasColorTail()) { msg.push_back(CStatusMessage(cats, CStatusMessage::SeverityWarning, "Livery: no tail color")); }
if (!getAirlineIcaoCodeDesignator().isEmpty()) { msg.push_back(m_airline.validate()); }
return msg;
}
int i = 0;
int dbKey = inner.at(i++).toInt(-1);
QString code(inner.at(i++).toString());
QString combinedCode(inner.at(i++).toString());
QString airlineWithId(inner.at(i++).toString());
QString airlineName(inner.at(i++).toString());
QString description(inner.at(i++).toString());
QString colorFuselage(normalizeHexColor(inner.at(i++).toString()));
QString colorTail(normalizeHexColor(inner.at(i++).toString()));
bool military = CDatastoreUtility::dbBoolStringToBool(inner.at(i++).toString());
bool CLivery::hasValidAirlineDesignator() const
{
return m_airline.hasValidDesignator();
}
int airlineId(CDatastoreUtility::extractIntegerKey(airlineWithId));
CAirlineIcaoCode airline;
airline.setDbKey(airlineId);
airline.setName(airlineName);
Q_ASSERT_X(code.length() > 0, Q_FUNC_INFO, "Missing code");
bool CLivery::hasCombinedCode() const
{
Q_ASSERT_X(!m_combinedCode.startsWith("." + standardLiveryMarker()), Q_FUNC_INFO, "illegal combined code");
return !m_combinedCode.isEmpty();
}
bool CLivery::isAirlineLivery() const
{
return (this->m_airline.hasValidDesignator());
}
bool CLivery::isAirlineStandardLivery() const
{
if (isColorLivery()) { return false; }
return (this->m_airline.hasValidDesignator() && this->m_combinedCode.endsWith(standardLiveryMarker()));
}
bool CLivery::isColorLivery() const
{
return m_combinedCode.startsWith(colorLiveryMarker());
}
CLivery CLivery::fromDatabaseJson(const QJsonObject &json, const QString &prefix)
{
if (!existsKey(json, prefix))
{
// when using relationship, this can be null
return CLivery();
}
QString combinedCode(json.value(prefix + "combinedcode").toString());
QString description(json.value(prefix + "description").toString());
CRgbColor colorFuselage(json.value(prefix + "colorfuselage").toString());
CRgbColor colorTail(json.value(prefix + "colortail").toString());
bool military = CDatastoreUtility::dbBoolStringToBool(json.value(prefix + "military").toString());
CAirlineIcaoCode airline(CAirlineIcaoCode::fromDatabaseJson(json, "al_"));
Q_ASSERT_X(description.length() > 0, Q_FUNC_INFO, "require description");
CLivery livery(dbKey, combinedCode, airline, description, colorFuselage, colorTail, military);
CLivery livery(combinedCode, airline, description, colorFuselage, colorTail, military);
livery.setKeyAndTimestampFromDatabaseJson(json, prefix);
return livery;
}
QString CLivery::normalizeHexColor(const QString &color)
bool CLivery::isValidCombinedCode(const QString &candidate)
{
if (color.isEmpty()) { return ""; }
QString c = color.trimmed().replace('#', "").toUpper();
return c;
if (candidate.isEmpty()) { return false; }
if (candidate.count('.') != 1) { return false; }
return candidate.length() > 2;
}
const QString &CLivery::standardLiveryMarker()
{
static const QString s("_STD");
return s;
}
const QString &CLivery::colorLiveryMarker()
{
static const QString s("_CC");
return s;
}
CVariant CLivery::propertyByIndex(const BlackMisc::CPropertyIndex &index) const
@@ -98,10 +182,12 @@ namespace BlackMisc
{
case IndexDescription:
return CVariant::fromValue(m_description);
case IndexAirlineIcaoCode:
return m_airline.propertyByIndex(index.copyFrontRemoved());
case IndexColorFuselage:
return CVariant::fromValue(this->m_colorFuselage);
return this->m_colorFuselage.propertyByIndex(index.copyFrontRemoved());;
case IndexColorTail:
return CVariant::fromValue(this->m_colorTail);
return this->m_colorTail.propertyByIndex(index.copyFrontRemoved());
case IndexCombinedCode:
return CVariant::fromValue(this->m_combinedCode);
case IndexIsMilitary:
@@ -121,11 +207,14 @@ namespace BlackMisc
case IndexDescription:
this->m_description = variant.toQString(false);
break;
case IndexAirlineIcaoCode:
this->m_airline.setPropertyByIndex(variant, index.copyFrontRemoved());
break;
case IndexColorFuselage:
this->setColorFuselage(variant.toQString(false));
this->m_colorFuselage.setPropertyByIndex(variant, index.copyFrontRemoved());
break;
case IndexColorTail:
this->setColorTail(variant.toQString(false));
this->m_colorTail.setPropertyByIndex(variant, index.copyFrontRemoved());
break;
case IndexCombinedCode:
this->setCombinedCode(variant.toQString(false));
@@ -139,5 +228,20 @@ namespace BlackMisc
}
}
void CLivery::updateMissingParts(const CLivery &otherLivery)
{
if (!this->m_colorFuselage.isValid()) { this->setColorFuselage(otherLivery.getColorFuselage()); }
if (!this->m_colorTail.isValid()) { this->setColorTail(otherLivery.getColorTail()); }
if (this->m_combinedCode.isEmpty()) { this->setCombinedCode(otherLivery.getCombinedCode());}
if (this->m_description.isEmpty()) { this->setDescription(otherLivery.getDescription());}
this->m_airline.updateMissingParts(otherLivery.getAirlineIcaoCode());
if (!this->hasValidDbKey())
{
this->setDbKey(otherLivery.getDbKey());
this->setUtcTimestamp(otherLivery.getUtcTimestamp());
}
}
} // namespace
} // namespace

View File

@@ -15,6 +15,7 @@
#include "blackmisc/blackmiscexport.h"
#include "blackmisc/aviation/airlineicaocode.h"
#include "blackmisc/geo/coordinategeodetic.h"
#include "blackmisc/rgbcolor.h"
#include "blackmisc/propertyindex.h"
#include "blackmisc/datastore.h"
@@ -32,6 +33,7 @@ namespace BlackMisc
enum ColumnIndex
{
IndexDescription = BlackMisc::CPropertyIndex::GlobalIndexCLivery,
IndexAirlineIcaoCode,
IndexCombinedCode,
IndexColorFuselage,
IndexColorTail,
@@ -41,14 +43,26 @@ namespace BlackMisc
//! Default constructor.
CLivery();
//! Constructor
CLivery(const QString &combinedCode, const CAirlineIcaoCode &airline, const QString &description);
//! Constructor
CLivery(const QString &combinedCode, const CAirlineIcaoCode &airline, const QString &description, const QString &colorFuselage, const QString &colorTail, bool isMilitary);
//! Constructor
CLivery(const QString &combinedCode, const CAirlineIcaoCode &airline, const QString &description, const BlackMisc::CRgbColor &colorFuselage, const BlackMisc::CRgbColor &colorTail, bool isMilitary);
//! Constructor
CLivery(int dbKey, const QString &combinedCode, const CAirlineIcaoCode &airline, const QString &description, const QString &colorFuselage, const QString &colorTail, bool isMilitary);
//! Constructor
CLivery(int dbKey, const QString &combinedCode, const CAirlineIcaoCode &airline, const QString &description, const BlackMisc::CRgbColor &colorFuselage, const BlackMisc::CRgbColor &colorTail, bool isMilitary);
//! Corresponding airline, if any
const CAirlineIcaoCode &getAirlineIcao() const { return m_airline; }
const CAirlineIcaoCode &getAirlineIcaoCode() const { return m_airline; }
//! Corresponding airline designator, if any
const QString &getAirlineIcaoCodeDesignator() const { return m_airline.getDesignator(); }
//! Combined code
const QString &getCombinedCode() const { return m_combinedCode; }
@@ -57,29 +71,41 @@ namespace BlackMisc
const QString &getDescription() const { return m_description; }
//! Get fuselage color.
const QString &getColorFuselage() const { return m_colorFuselage; }
const BlackMisc::CRgbColor &getColorFuselage() const { return m_colorFuselage; }
//! Get tail color.
const QString &getColorTails() const { return m_colorTail; }
const BlackMisc::CRgbColor &getColorTail() const { return m_colorTail; }
//! Military livery
bool isMilitary() const { return m_military; }
//! Airline ICAO code
void setAirlineIcao(const CAirlineIcaoCode &airlineIcao) { m_airline = airlineIcao; }
bool setAirlineIcaoCode(const CAirlineIcaoCode &airlineIcao);
//! Combined code
void setCombinedCode(const QString &code) { m_combinedCode = code.trimmed().toUpper(); }
//! Set fuselage color
void setColorFuselage(const QString &color) { this->m_colorFuselage = normalizeHexColor(color); }
void setColorFuselage(const BlackMisc::CRgbColor &color) { this->m_colorFuselage = color; }
//! Set tail color
void setColorTail(const QString &color) { this->m_colorTail = normalizeHexColor(color); }
void setColorTail(const BlackMisc::CRgbColor &color) { this->m_colorTail = color; }
//! Fuselage color set?
bool hasColorFuselage() const;
//! Tail color set?
bool hasColorTail() const;
//! Set description
void setDescription(const QString &description) { this->m_description = description; }
//! Military aircraft?
void setMilitary(bool isMilitary) { this->m_military = isMilitary; }
//! Matches combined code
bool matchesCombinedCode(const QString &candidate) const;
//! \copydoc CValueObject::propertyByIndex
CVariant propertyByIndex(const BlackMisc::CPropertyIndex &index) const;
@@ -92,31 +118,59 @@ namespace BlackMisc
//! Complete data?
bool hasCompleteData() const;
//! Validate data
BlackMisc::CStatusMessageList validate() const;
//! Airline available?
bool hasValidAirlineDesignator() const;
//! Livery combined code available?
bool hasCombinedCode() const;
//! Livery representing airline
bool isAirlineLivery() const;
//! Livery representing airline standard livery
bool isAirlineStandardLivery() const;
//! Color livery
bool isColorLivery() const;
//! Update missing parts
void updateMissingParts(const CLivery &otherLivery);
//! Object from JSON
static CLivery fromDatabaseJson(const QJsonObject &json);
static CLivery fromDatabaseJson(const QJsonObject &json, const QString &prefix = QString("liv_"));
//! Valid combined code string?
static bool isValidCombinedCode(const QString &candidate);
//! Standard livery marker
static const QString &standardLiveryMarker();
//! Color livery marker
static const QString &colorLiveryMarker();
private:
BLACK_ENABLE_TUPLE_CONVERSION(CLivery)
int m_dbKey = -1; //!< optional DB key
CAirlineIcaoCode m_airline; //!< corresponding airline, if any
QString m_combinedCode; //!< livery code and pseudo airline ICAO code
QString m_description;
QString m_colorFuselage;
QString m_colorTail;
QString m_description; //!< describes the livery
BlackMisc::CRgbColor m_colorFuselage; //! color of fuselage
BlackMisc::CRgbColor m_colorTail; //! color of tail
bool m_military = false; //! Military livery?
static QString normalizeHexColor(const QString &color);
};
} // namespace
} // namespace
BLACK_DECLARE_TUPLE_CONVERSION(BlackMisc::Aviation::CLivery, (
attr(o.m_dbKey),
attr(o.m_timestampMSecsSinceEpoch),
attr(o.m_airline),
attr(o.m_combinedCode, flags <CaseInsensitiveComparison> ()),
attr(o.m_description),
attr(o.m_colorFuselage, flags <CaseInsensitiveComparison> ()),
attr(o.m_colorTail, flags <CaseInsensitiveComparison> ())
attr(o.m_colorFuselage),
attr(o.m_colorTail)
))
Q_DECLARE_METATYPE(BlackMisc::Aviation::CLivery)

View File

@@ -23,11 +23,32 @@ namespace BlackMisc
CSequence<CLivery>(other)
{ }
CLiveryList CLiveryList::findByCombinedCode(const QString &combinedCode) const
CLiveryList CLiveryList::findByAirlineIcaoDesignator(const QString &icao) const
{
QString cc(combinedCode.trimmed().toUpper());
if (cc.isEmpty()) { return CLiveryList();}
return this->findBy(&CLivery::getCombinedCode, cc);
QString i(icao.trimmed().toUpper());
if (i.isEmpty()) { return CLiveryList(); }
return this->findBy(&CLivery::getAirlineIcaoCodeDesignator, i);
}
CLivery CLiveryList::findByAirlineIcaoDesignatorStdLivery(const QString &icao) const
{
QString i(icao.trimmed().toUpper());
if (i.isEmpty()) { return CLivery(); }
return this->findFirstByOrDefault([&](const CLivery & livery)
{
return livery.getAirlineIcaoCodeDesignator() == icao &&
livery.isAirlineStandardLivery();
});
}
CLivery CLiveryList::findByCombinedCode(const QString &combinedCode) const
{
if (!CLivery::isValidCombinedCode(combinedCode)) { return CLivery(); }
return this->findFirstByOrDefault([&](const CLivery & livery)
{
return livery.matchesCombinedCode(combinedCode);
});
}
} // namespace

View File

@@ -36,9 +36,14 @@ namespace BlackMisc
//! Construct from a base class object.
CLiveryList(const CSequence<CLivery> &other);
//! Find 0..n liveries by combined code
CLiveryList findByCombinedCode(const QString &combinedCode) const;
//! Find livery by airline
CLiveryList findByAirlineIcaoDesignator(const QString &icao) const;
//! Find livery by airline
CLivery findByAirlineIcaoDesignatorStdLivery(const QString &icao) const;
//! Find livery by combined code
CLivery findByCombinedCode(const QString &combinedCode) const;
};
} //namespace
} // namespace