diff --git a/src/blackmisc/aviation/aircrafticaocode.cpp b/src/blackmisc/aviation/aircrafticaocode.cpp index 0dd8b9606..b90b89706 100644 --- a/src/blackmisc/aviation/aircrafticaocode.cpp +++ b/src/blackmisc/aviation/aircrafticaocode.cpp @@ -55,6 +55,18 @@ namespace BlackMisc if (m_rank < 0 || m_rank >= 10) { m_rank = 10; } } + QString CAircraftIcaoCode::getDesignatorDbKey() const + { + if (this->isLoadedFromDb()) + { + return this->getDesignator() + " " + this->getDbKeyAsStringInParentheses(); + } + else + { + return this->getDesignator(); + } + } + QString CAircraftIcaoCode::convertToQString(bool i18n) const { Q_UNUSED(i18n); diff --git a/src/blackmisc/aviation/aircrafticaocode.h b/src/blackmisc/aviation/aircrafticaocode.h index 20cdee3da..4f69433d1 100644 --- a/src/blackmisc/aviation/aircrafticaocode.h +++ b/src/blackmisc/aviation/aircrafticaocode.h @@ -71,6 +71,9 @@ namespace BlackMisc //! Get ICAO designator, e.g. "B737" const QString &getDesignator() const { return m_designator; } + //! Designator and DB key + QString getDesignatorDbKey() const; + //! Set ICAO designator, e.g. "B737" void setDesignator(const QString &icaoDesignator) { this->m_designator = icaoDesignator.trimmed().toUpper(); } diff --git a/src/blackmisc/aviation/aircrafticaocodelist.cpp b/src/blackmisc/aviation/aircrafticaocodelist.cpp index c82ecf631..3020488c6 100644 --- a/src/blackmisc/aviation/aircrafticaocodelist.cpp +++ b/src/blackmisc/aviation/aircrafticaocodelist.cpp @@ -192,6 +192,19 @@ namespace BlackMisc return c.toList(); } + QStringList CAircraftIcaoCodeList::allManufacturers(bool onlyKnownDesignators) const + { + QStringList c; + for (const CAircraftIcaoCode &icao : *this) + { + if (onlyKnownDesignators && !icao.hasKnownDesignator()) { continue; } + const QString m(icao.getManufacturer()); + if (m.isEmpty() || c.contains(m)) { continue; } + c.append(m); + } + return c; + } + CAircraftIcaoCodeList CAircraftIcaoCodeList::fromDatabaseJson(const QJsonArray &array, bool ignoreIncomplete) { CAircraftIcaoCodeList codes; diff --git a/src/blackmisc/aviation/aircrafticaocodelist.h b/src/blackmisc/aviation/aircrafticaocodelist.h index a61b25b41..6b154b432 100644 --- a/src/blackmisc/aviation/aircrafticaocodelist.h +++ b/src/blackmisc/aviation/aircrafticaocodelist.h @@ -94,6 +94,9 @@ namespace BlackMisc //! All ICAO codes, no duplicates QStringList allIcaoCodes(bool noUnspecified = true) const; + //! All manufacturers + QStringList allManufacturers(bool onlyKnownDesignators = true) const; + //! From our database JSON format static CAircraftIcaoCodeList fromDatabaseJson(const QJsonArray &array, bool ignoreIncomplete = true); }; diff --git a/src/blackmisc/aviation/airlineicaocode.cpp b/src/blackmisc/aviation/airlineicaocode.cpp index e806aa4ef..fe2fd0f24 100644 --- a/src/blackmisc/aviation/airlineicaocode.cpp +++ b/src/blackmisc/aviation/airlineicaocode.cpp @@ -56,6 +56,18 @@ namespace BlackMisc return QString("V").append(this->m_designator); } + QString CAirlineIcaoCode::getVDesignatorDbKey() const + { + if (this->isLoadedFromDb()) + { + return this->getVDesignator() + " " + this->getDbKeyAsStringInParentheses(); + } + else + { + return this->getVDesignator(); + } + } + void CAirlineIcaoCode::setDesignator(const QString &icaoDesignator) { this->m_designator = icaoDesignator.trimmed().toUpper(); @@ -286,7 +298,7 @@ namespace BlackMisc bool CAirlineIcaoCode::isValidAirlineDesignator(const QString &airline) { // allow 2 chars for IATA - if (airline.length() < 2 || airline.length() > 5) return false; + if (airline.length() < 2 || airline.length() > 5) { return false; } auto chars = makeRange(airline.begin(), airline.end()); if (chars.containsBy([](QChar c) { return !c.isUpper() && !c.isDigit(); })) { return false; } return true; @@ -377,11 +389,16 @@ namespace BlackMisc { if (!existsKey(json, prefix)) { - // when using relationship, this can be null + // when using relationship, this can be null (e.g. for color liveries) return CAirlineIcaoCode(); } - const QString designator(json.value(prefix + "designator").toString()); + QString designator(json.value(prefix + "designator").toString()); + if (!CAirlineIcaoCode::isValidAirlineDesignator(designator)) + { + designator = CAirlineIcaoCode::normalizeDesignator(designator); + } + const QString iata(json.value(prefix + "iata").toString()); const QString telephony(json.value(prefix + "callsign").toString()); const QString name(json.value(prefix + "name").toString()); diff --git a/src/blackmisc/aviation/airlineicaocode.h b/src/blackmisc/aviation/airlineicaocode.h index 775a8939c..093f971ad 100644 --- a/src/blackmisc/aviation/airlineicaocode.h +++ b/src/blackmisc/aviation/airlineicaocode.h @@ -68,6 +68,9 @@ namespace BlackMisc //! Get airline, e.g. "DLH", but "VMVA" for virtual airlines const QString getVDesignator() const; + //! Get VDesignator plus key + QString getVDesignatorDbKey() const; + //! Set airline, e.g. "DLH" void setDesignator(const QString &icaoDesignator); diff --git a/src/blackmisc/aviation/livery.cpp b/src/blackmisc/aviation/livery.cpp index 2e05bcf91..46ec1c856 100644 --- a/src/blackmisc/aviation/livery.cpp +++ b/src/blackmisc/aviation/livery.cpp @@ -17,6 +17,7 @@ #include "blackmisc/statusmessage.h" #include "blackmisc/stringutils.h" #include "blackmisc/variant.h" +#include "blackmisc/verify.h" #include #include @@ -208,21 +209,27 @@ namespace BlackMisc return CLivery(); } - QString combinedCode(json.value(prefix + "combinedcode").toString()); + const QString combinedCode(json.value(prefix + "combinedcode").toString()); if (combinedCode.isEmpty()) { - CLivery liveryStub; // only consists of id, maybe id and timestamp + CLivery liveryStub; // only consists of id, maybe key and timestamp liveryStub.setKeyAndTimestampFromDatabaseJson(json, prefix); return liveryStub; } - 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_")); + const bool isColorLivery = combinedCode.startsWith(colorLiveryMarker()); + const QString description(json.value(prefix + "description").toString()); + const CRgbColor colorFuselage(json.value(prefix + "colorfuselage").toString()); + const CRgbColor colorTail(json.value(prefix + "colortail").toString()); + const bool military = CDatastoreUtility::dbBoolStringToBool(json.value(prefix + "military").toString()); + CAirlineIcaoCode airline; + if (!isColorLivery) { airline = CAirlineIcaoCode::fromDatabaseJson(json, "al_"); } CLivery livery(combinedCode, airline, description, colorFuselage, colorTail, military); livery.setKeyAndTimestampFromDatabaseJson(json, prefix); + + // color liveries must have default ICAO, but airline liveries must have DB airline + BLACK_VERIFY_X((livery.isColorLivery() && !livery.getAirlineIcaoCode().hasValidDbKey()) || (livery.isAirlineLivery() && livery.getAirlineIcaoCode().hasValidDbKey()), Q_FUNC_INFO, "inconsistent data"); + return livery; } diff --git a/src/blackmisc/db/datastore.cpp b/src/blackmisc/db/datastore.cpp index 18b5219f3..927908925 100644 --- a/src/blackmisc/db/datastore.cpp +++ b/src/blackmisc/db/datastore.cpp @@ -76,7 +76,7 @@ namespace BlackMisc void IDatastoreObjectWithIntegerKey::setKeyAndTimestampFromDatabaseJson(const QJsonObject &json, const QString &prefix) { - int dbKey = json.value(prefix + "id").toInt(-1); + const int dbKey = json.value(prefix + "id").toInt(-1); const QString timestampString(json.value(prefix + "lastupdated").toString()); const QDateTime ts(CDatastoreUtility::parseTimestamp(timestampString)); this->setDbKey(dbKey); @@ -85,7 +85,8 @@ namespace BlackMisc bool IDatastoreObjectWithIntegerKey::existsKey(const QJsonObject &json, const QString &prefix) { - return !json.value(prefix + "id").isNull(); + const QJsonValue jv(json.value(prefix + "id")); + return !(jv.isNull() || jv.isUndefined()); } CVariant IDatastoreObjectWithIntegerKey::propertyByIndex(const CPropertyIndex &index) const @@ -166,7 +167,8 @@ namespace BlackMisc bool IDatastoreObjectWithStringKey::existsKey(const QJsonObject &json, const QString &prefix) { - return !json.value(prefix + "id").isNull(); + const QJsonValue jv(json.value(prefix + "id")); + return !(jv.isNull() || jv.isUndefined()); } CVariant IDatastoreObjectWithStringKey::propertyByIndex(const CPropertyIndex &index) const diff --git a/src/blackmisc/simulation/distributor.cpp b/src/blackmisc/simulation/distributor.cpp index 734474fde..8e24f1f6f 100644 --- a/src/blackmisc/simulation/distributor.cpp +++ b/src/blackmisc/simulation/distributor.cpp @@ -134,7 +134,7 @@ namespace BlackMisc static const CLogCategoryList cats(CLogCategoryList(this).join({ CLogCategory::validation() })); CStatusMessageList msgs; if (!hasValidDbKey()) { msgs.push_back(CStatusMessage(cats, CStatusMessage::SeverityError, "Distributor: missing id")); } - if (!hasDescription()) { msgs.push_back(CStatusMessage(cats, CStatusMessage::SeverityWarning, "Distributor: missing description")); } + if (!hasDescription()) { msgs.push_back(CStatusMessage(cats, CStatusMessage::SeverityError, "Distributor: missing description")); } return msgs; }