diff --git a/src/blackmisc/aviation/airlineicaocode.cpp b/src/blackmisc/aviation/airlineicaocode.cpp index af981124b..70d9be6c9 100644 --- a/src/blackmisc/aviation/airlineicaocode.cpp +++ b/src/blackmisc/aviation/airlineicaocode.cpp @@ -317,13 +317,19 @@ namespace BlackMisc bool CAirlineIcaoCode::isValidAirlineDesignator(const QString &airline) { - // allow 2 chars for IATA + // allow 2 chars for special codes like "VV" if (airline.length() < 2 || airline.length() > 5) { return false; } const auto chars = makeRange(airline.begin(), airline.end()); if (chars.containsBy([](QChar c) { return !c.isUpper() && !c.isDigit(); })) { return false; } return true; } + bool CAirlineIcaoCode::isValidIataCode(const QString &iataCode) + { + if (iataCode.length() != 2) { return false; } + return isValidAirlineDesignator(iataCode); // allow some chars as in IACO + } + QSet CAirlineIcaoCode::specialValidDesignators() { static const QSet valid({ "VV", "VM"}); diff --git a/src/blackmisc/aviation/airlineicaocode.h b/src/blackmisc/aviation/airlineicaocode.h index 215f2f566..9962d07b0 100644 --- a/src/blackmisc/aviation/airlineicaocode.h +++ b/src/blackmisc/aviation/airlineicaocode.h @@ -228,6 +228,9 @@ namespace BlackMisc //! Valid designator? static bool isValidAirlineDesignator(const QString &airline); + //! Valid IATA code? + static bool isValidIataCode(const QString &iataCode); + //! Some special valid designator which do not fit standard rule (e.g. 3-letter code) static QSet specialValidDesignators(); diff --git a/src/blackmisc/aviation/airlineicaocodelist.cpp b/src/blackmisc/aviation/airlineicaocodelist.cpp index 1474fed9a..a602cbfdb 100644 --- a/src/blackmisc/aviation/airlineicaocodelist.cpp +++ b/src/blackmisc/aviation/airlineicaocodelist.cpp @@ -36,13 +36,19 @@ namespace BlackMisc CAirlineIcaoCodeList CAirlineIcaoCodeList::findByIataCode(const QString &iata) const { - if (iata.isEmpty()) { return CAirlineIcaoCodeList(); } + if (!CAirlineIcaoCode::isValidIataCode(iata)) { return CAirlineIcaoCodeList(); } return this->findBy([&](const CAirlineIcaoCode & code) { return code.matchesIataCode(iata); }); } + CAirlineIcaoCode CAirlineIcaoCodeList::findByUniqueIataCodeOrDefault(const QString &iata) const + { + const CAirlineIcaoCodeList codes = this->findByIataCode(iata); + return codes.size() == 1 ? codes.front() : CAirlineIcaoCode(); + } + CAirlineIcaoCodeList CAirlineIcaoCodeList::findByDesignatorOrIataCode(const QString &designatorOrIata) const { if (designatorOrIata.isEmpty()) { return CAirlineIcaoCodeList(); } @@ -61,6 +67,16 @@ namespace BlackMisc }); } + CAirlineIcaoCode CAirlineIcaoCodeList::findByUniqueVDesignatorOrDefault(const QString &designator, bool preferOperatingAirlines) const + { + CAirlineIcaoCodeList codes = this->findByVDesignator(designator); + if (codes.size() > 1 && preferOperatingAirlines) + { + codes.removeIf(&CAirlineIcaoCode::isOperating, false); + } + return codes.size() == 1 ? codes.front() : CAirlineIcaoCode(); + } + CAirlineIcaoCodeList CAirlineIcaoCodeList::findByVDesignatorOrIataCode(const QString &designatorOrIata) const { if (designatorOrIata.isEmpty()) { return CAirlineIcaoCodeList(); } @@ -262,5 +278,12 @@ namespace BlackMisc if (designator.isEmpty()) { return false; } return this->contains(&CAirlineIcaoCode::getDesignator, designator.toUpper()); } + + bool CAirlineIcaoCodeList::containsVDesignator(const QString &vDesignator) const + { + if (vDesignator.isEmpty()) { return false; } + if (vDesignator.length() < 4) { return this->containsDesignator(vDesignator); } + return this->contains(&CAirlineIcaoCode::getVDesignator, vDesignator.toUpper()); + } } // ns } // ns diff --git a/src/blackmisc/aviation/airlineicaocodelist.h b/src/blackmisc/aviation/airlineicaocodelist.h index 68464e158..c25147cd4 100644 --- a/src/blackmisc/aviation/airlineicaocodelist.h +++ b/src/blackmisc/aviation/airlineicaocodelist.h @@ -52,10 +52,16 @@ namespace BlackMisc //! Find by v-designator, this should be unique CAirlineIcaoCodeList findByVDesignator(const QString &designator) const; + //! Find by ICAO code if this is unique, otherwise return default object + CAirlineIcaoCode findByUniqueVDesignatorOrDefault(const QString &designator, bool preferOperatingAirlines) const; + //! Find by IATA code - //! Not unique because of virtual airlines + //! Not unique because of virtual airlines and ceased airlines CAirlineIcaoCodeList findByIataCode(const QString &iata) const; + //! Find by IATA code if this is unique, otherwise return default object + CAirlineIcaoCode findByUniqueIataCodeOrDefault(const QString &iata) const; + //! Find by designator or IATA code CAirlineIcaoCodeList findByDesignatorOrIataCode(const QString &designatorOrIata) const; @@ -98,6 +104,9 @@ namespace BlackMisc //! Contains given designator? bool containsDesignator(const QString &designator) const; + //! Contains given designator? + bool containsVDesignator(const QString &vDesignator) const; + //! From our DB JSON static CAirlineIcaoCodeList fromDatabaseJson(const QJsonArray &array, bool ignoreIncomplete = true, CAirlineIcaoCodeList *inconsistent = nullptr); }; diff --git a/src/blackmisc/aviation/callsign.h b/src/blackmisc/aviation/callsign.h index 28f597a46..95a858149 100644 --- a/src/blackmisc/aviation/callsign.h +++ b/src/blackmisc/aviation/callsign.h @@ -134,6 +134,9 @@ namespace BlackMisc //! Valid callsign? static bool isValidAtcCallsign(const CCallsign &callsign); + //! Unify the callsign by removing illegal characters + static QString unifyCallsign(const QString &callsign); + //! List of real ATC suffixes (e.g. TWR); static const QStringList &atcCallsignSuffixes(); @@ -161,10 +164,6 @@ namespace BlackMisc //! \copydoc BlackMisc::Mixin::String::toQString() QString convertToQString(bool i18n = false) const; - protected: - //! Unify the callsign - static QString unifyCallsign(const QString &callsign); - private: QString m_callsignAsSet; QString m_callsign; diff --git a/src/blackmisc/aviation/selcal.cpp b/src/blackmisc/aviation/selcal.cpp index 7432e197a..b1242735f 100644 --- a/src/blackmisc/aviation/selcal.cpp +++ b/src/blackmisc/aviation/selcal.cpp @@ -33,7 +33,7 @@ namespace BlackMisc { if (CSelcal::isValidCharacter(c)) { s += c;} } - return s.length() == 4 ? s : QString(""); + return CSelcal::isValidCode(s) ? s : QString(""); } bool CSelcal::equalsString(const QString &code) const @@ -83,8 +83,8 @@ namespace BlackMisc { int pos = CSelcal::validCharacters().indexOf(c); Q_ASSERT(pos >= 0); - Q_ASSERT(CSelcal::frequencyEquivalents.size() > pos); - return CSelcal::frequencyEquivalents[pos]; + Q_ASSERT(CSelcal::audioFrequencyEquivalents().size() > pos); + return CSelcal::audioFrequencyEquivalents()[pos]; } const QList &CSelcal::audioFrequencyEquivalents() diff --git a/src/blackmisc/aviation/selcal.h b/src/blackmisc/aviation/selcal.h index cf40298bb..3e71ece04 100644 --- a/src/blackmisc/aviation/selcal.h +++ b/src/blackmisc/aviation/selcal.h @@ -70,12 +70,6 @@ namespace BlackMisc //! Valid SELCAL code? static bool isValidCode(const QString &code); - //! Audio frequency for character - static const PhysicalQuantities::CFrequency &audioFrequencyEquivalent(QChar c); - - //! All audio frequencies - static const QList &audioFrequencyEquivalents(); - //! All valid code pairs: AB, AC, AD ... static const QStringList &codePairs(); @@ -83,6 +77,12 @@ namespace BlackMisc static QString unifyCode(const QString &selcalCandidate); private: + //! Audio frequency for character + static const PhysicalQuantities::CFrequency &audioFrequencyEquivalent(QChar c); + + //! All audio frequencies + static const QList &audioFrequencyEquivalents(); + QString m_code; BLACK_METACLASS(