Ref T637, allow 3 letter ICAOs in FP

* strict or lenient airport check
* allow to enter 3 letter ICAO codes in FP
This commit is contained in:
Klaus Basan
2019-04-27 20:00:47 +02:00
parent 0eed0f0f00
commit c56775e815
9 changed files with 54 additions and 18 deletions

View File

@@ -123,7 +123,7 @@ namespace BlackGui
if (m_current.isNull()) if (m_current.isNull())
{ {
const QString icao = this->getIcaoText(); const QString icao = this->getIcaoText();
if (CAirportIcaoCode::isValidIcaoDesignator(icao)) if (CAirportIcaoCode::isValidIcaoDesignator(icao, true))
{ {
const CAirport airport = sGui->getWebDataServices()->getAirportForIcaoDesignator(icao); const CAirport airport = sGui->getWebDataServices()->getAirportForIcaoDesignator(icao);
if (!airport.isNull()) { this->setAirport(airport); } if (!airport.isNull()) { this->setAirport(airport); }

View File

@@ -115,7 +115,7 @@ namespace BlackGui
if (m_current.isNull()) if (m_current.isNull())
{ {
const QString icao = this->getIcaoText(); const QString icao = this->getIcaoText();
if (CAirportIcaoCode::isValidIcaoDesignator(icao)) if (CAirportIcaoCode::isValidIcaoDesignator(icao, true))
{ {
const CAirport airport = sGui->getWebDataServices()->getAirportForIcaoDesignator(icao); const CAirport airport = sGui->getWebDataServices()->getAirportForIcaoDesignator(icao);
if (!airport.isNull()) { this->setAirport(airport); } if (!airport.isNull()) { this->setAirport(airport); }

View File

@@ -266,7 +266,7 @@ namespace BlackGui
if (!this->canAccessContext()) { return; } if (!this->canAccessContext()) { return; }
const CAirportIcaoCode icao(airportIcaoCode.isEmpty() ? ui->le_AtcStationsOnlineMetar->text().trimmed().toUpper() : airportIcaoCode.trimmed().toUpper()); const CAirportIcaoCode icao(airportIcaoCode.isEmpty() ? ui->le_AtcStationsOnlineMetar->text().trimmed().toUpper() : airportIcaoCode.trimmed().toUpper());
ui->le_AtcStationsOnlineMetar->setText(icao.asString()); ui->le_AtcStationsOnlineMetar->setText(icao.asString());
if (!icao.hasValidIcaoCode()) { return; } if (!icao.hasValidIcaoCode(true)) { return; }
const CMetar metar(sGui->getIContextNetwork()->getMetarForAirport(icao)); const CMetar metar(sGui->getIContextNetwork()->getMetarForAirport(icao));
if (metar.hasMessage()) if (metar.hasMessage())
{ {

View File

@@ -399,6 +399,14 @@ namespace BlackGui
else else
{ {
flightPlan.setDestinationAirportIcao(v); flightPlan.setDestinationAirportIcao(v);
if (strict && !flightPlan.getDestinationAirportIcao().hasValidIcaoCode(true))
{
messages.push_back(CStatusMessage(this).validationError(u"Invalid destination ICAO code '%1'") << v);
}
else if (!flightPlan.getDestinationAirportIcao().hasValidIcaoCode(false))
{
messages.push_back(CStatusMessage(this).validationWarning(u"Wrong or missing '%1'") << ui->lbl_DestinationAirport->text());
}
} }
// origin airport // origin airport
@@ -411,6 +419,14 @@ namespace BlackGui
else else
{ {
flightPlan.setOriginAirportIcao(v); flightPlan.setOriginAirportIcao(v);
if (strict && !flightPlan.getOriginAirportIcao().hasValidIcaoCode(true))
{
messages.push_back(CStatusMessage(this).validationError(u"Invalid origin ICAO code '%1'") << v);
}
else if (!flightPlan.getOriginAirportIcao().hasValidIcaoCode(false))
{
messages.push_back(CStatusMessage(this).validationWarning(u"Wrong or missing '%1'") << ui->lbl_DestinationAirport->text());
}
} }
// TAS // TAS

View File

@@ -61,32 +61,38 @@ namespace BlackGui
// shortcuts // shortcuts
QShortcut *filter = new QShortcut(CShortcut::keyDisplayFilter(), this); QShortcut *filter = new QShortcut(CShortcut::keyDisplayFilter(), this);
connect(filter, &QShortcut::activated, this, &CViewBaseNonTemplate::displayFilterDialog); bool s = connect(filter, &QShortcut::activated, this, &CViewBaseNonTemplate::displayFilterDialog);
Q_ASSERT_X(s, Q_FUNC_INFO, "Shortcut");
filter->setObjectName("Filter shortcut for " + this->objectName()); filter->setObjectName("Filter shortcut for " + this->objectName());
filter->setContext(Qt::WidgetShortcut); filter->setContext(Qt::WidgetShortcut);
QShortcut *clearSelection = new QShortcut(CShortcut::keyClearSelection(), this); QShortcut *clearSelection = new QShortcut(CShortcut::keyClearSelection(), this);
connect(clearSelection, &QShortcut::activated, this, &CViewBaseNonTemplate::clearSelection); s = connect(clearSelection, &QShortcut::activated, this, &CViewBaseNonTemplate::clearSelection);
Q_ASSERT_X(s, Q_FUNC_INFO, "Shortcut");
clearSelection->setObjectName("Clear selection shortcut for " + this->objectName()); clearSelection->setObjectName("Clear selection shortcut for " + this->objectName());
clearSelection->setContext(Qt::WidgetShortcut); clearSelection->setContext(Qt::WidgetShortcut);
QShortcut *saveJson = new QShortcut(CShortcut::keySaveViews(), this); QShortcut *saveJson = new QShortcut(CShortcut::keySaveViews(), this);
connect(saveJson, &QShortcut::activated, this, &CViewBaseNonTemplate::saveJsonAction); s = connect(saveJson, &QShortcut::activated, this, &CViewBaseNonTemplate::saveJsonAction);
Q_ASSERT_X(s, Q_FUNC_INFO, "Shortcut");
saveJson->setObjectName("Save JSON for " + this->objectName()); saveJson->setObjectName("Save JSON for " + this->objectName());
saveJson->setContext(Qt::WidgetShortcut); saveJson->setContext(Qt::WidgetShortcut);
QShortcut *deleteRow = new QShortcut(CShortcut::keyDelete(), this); QShortcut *deleteRow = new QShortcut(CShortcut::keyDelete(), this);
connect(deleteRow, &QShortcut::activated, this, &CViewBaseNonTemplate::removeSelectedRowsChecked); s = connect(deleteRow, &QShortcut::activated, this, &CViewBaseNonTemplate::removeSelectedRowsChecked);
Q_ASSERT_X(s, Q_FUNC_INFO, "Shortcut");
deleteRow->setObjectName("Remove selected rows for " + this->objectName()); deleteRow->setObjectName("Remove selected rows for " + this->objectName());
deleteRow->setContext(Qt::WidgetShortcut); deleteRow->setContext(Qt::WidgetShortcut);
QShortcut *copy = new QShortcut(CShortcut::keyCopy(), this); QShortcut *copy = new QShortcut(CShortcut::keyCopy(), this);
connect(copy, &QShortcut::activated, this, &CViewBaseNonTemplate::copy); s = connect(copy, &QShortcut::activated, this, &CViewBaseNonTemplate::copy);
Q_ASSERT_X(s, Q_FUNC_INFO, "Shortcut");
copy->setObjectName("Copy selection shortcut for " + this->objectName()); copy->setObjectName("Copy selection shortcut for " + this->objectName());
copy->setContext(Qt::WidgetShortcut); copy->setContext(Qt::WidgetShortcut);
QShortcut *resize = new QShortcut(CShortcut::keyResizeView(), this); QShortcut *resize = new QShortcut(CShortcut::keyResizeView(), this);
connect(resize, &QShortcut::activated, this, &CViewBaseNonTemplate::resizeToContents); s = connect(resize, &QShortcut::activated, this, &CViewBaseNonTemplate::fullResizeToContents);
Q_ASSERT_X(s, Q_FUNC_INFO, "Shortcut");
resize->setObjectName("Resize view shortcut for " + this->objectName()); resize->setObjectName("Resize view shortcut for " + this->objectName());
resize->setContext(Qt::WidgetShortcut); resize->setContext(Qt::WidgetShortcut);
} }

View File

@@ -15,9 +15,9 @@ namespace BlackMisc
return m_icaoCode; return m_icaoCode;
} }
bool CAirportIcaoCode::hasValidIcaoCode() const bool CAirportIcaoCode::hasValidIcaoCode(bool strict) const
{ {
return CAirportIcaoCode::isValidIcaoDesignator(this->getIcaoCode()); return CAirportIcaoCode::isValidIcaoDesignator(this->getIcaoCode(), strict);
} }
bool CAirportIcaoCode::equalsString(const QString &icaoCode) const bool CAirportIcaoCode::equalsString(const QString &icaoCode) const
@@ -29,15 +29,15 @@ namespace BlackMisc
QString CAirportIcaoCode::unifyAirportCode(const QString &icaoCode) QString CAirportIcaoCode::unifyAirportCode(const QString &icaoCode)
{ {
const QString code = icaoCode.trimmed().toUpper(); const QString code = icaoCode.trimmed().toUpper();
if (code.length() != 4) return {}; if (!validCodeLength(icaoCode.length(), false)) return {};
if (containsChar(code, [](QChar c) { return !c.isLetterOrNumber(); })) { return {}; } if (containsChar(code, [](QChar c) { return !c.isLetterOrNumber(); })) { return {}; }
return code; return code;
} }
bool CAirportIcaoCode::isValidIcaoDesignator(const QString &icaoCode) bool CAirportIcaoCode::isValidIcaoDesignator(const QString &icaoCode, bool strict)
{ {
const QString icao = unifyAirportCode(icaoCode); const QString icao = unifyAirportCode(icaoCode);
return icao.length() == 4; return validCodeLength(icao.length(), strict);
} }
bool CAirportIcaoCode::containsNumbers(const QString &icaoCode) bool CAirportIcaoCode::containsNumbers(const QString &icaoCode)
@@ -63,5 +63,16 @@ namespace BlackMisc
return m_icaoCode.compare(compareValue.getIcaoCode(), Qt::CaseInsensitive); return m_icaoCode.compare(compareValue.getIcaoCode(), Qt::CaseInsensitive);
} }
bool CAirportIcaoCode::validCodeLength(int l, bool strict)
{
// FAA code 3
// ICAO code 4
if (strict) { return l == 4; }
return l >= 3 && l <= 6;
// https://en.wikipedia.org/wiki/Location_identifier#FAA_identifier says can be up to 5 characters
// https://en.wikipedia.org/wiki/ICAO_airport_code#Pseudo_ICAO-codes says France has some 6-character airport codes
// and ZZZZ can be used in a flight plan as ICAO code for any airport that doesn't have one
}
} // namespace } // namespace
} // namespace } // namespace

View File

@@ -41,7 +41,7 @@ namespace BlackMisc
bool isEmpty() const { return this->m_icaoCode.isEmpty(); } bool isEmpty() const { return this->m_icaoCode.isEmpty(); }
//! Has valid code? //! Has valid code?
bool hasValidIcaoCode() const; bool hasValidIcaoCode(bool strict) const;
//! Get code. //! Get code.
const QString &asString() const { return this->m_icaoCode; } const QString &asString() const { return this->m_icaoCode; }
@@ -56,7 +56,7 @@ namespace BlackMisc
static QString unifyAirportCode(const QString &icaoCode); static QString unifyAirportCode(const QString &icaoCode);
//! Valid ICAO designator //! Valid ICAO designator
static bool isValidIcaoDesignator(const QString &icaoCode); static bool isValidIcaoDesignator(const QString &icaoCode, bool strict);
//! Containing numbers (normally indicator for small airfield/strip) //! Containing numbers (normally indicator for small airfield/strip)
static bool containsNumbers(const QString &icaoCode); static bool containsNumbers(const QString &icaoCode);
@@ -73,6 +73,9 @@ namespace BlackMisc
//! \copydoc BlackMisc::Mixin::Index::comparePropertyByIndex //! \copydoc BlackMisc::Mixin::Index::comparePropertyByIndex
int comparePropertyByIndex(const CPropertyIndex &index, const CAirportIcaoCode &compareValue) const; int comparePropertyByIndex(const CPropertyIndex &index, const CAirportIcaoCode &compareValue) const;
//! Valid code lenght
static bool validCodeLength(int l, bool strict);
private: private:
QString m_icaoCode; QString m_icaoCode;

View File

@@ -138,7 +138,7 @@ namespace BlackMisc
bool CUser::hasValidHomeBase() const bool CUser::hasValidHomeBase() const
{ {
return m_homebase.hasValidIcaoCode(); return m_homebase.hasValidIcaoCode(false);
} }
CStatusMessageList CUser::validate() const CStatusMessageList CUser::validate() const

View File

@@ -362,7 +362,7 @@ namespace BlackSimPlugin
if (!pFacilityAirport) { break; } if (!pFacilityAirport) { break; }
const QString icao(pFacilityAirport->Icao); const QString icao(pFacilityAirport->Icao);
if (icao.isEmpty()) { continue; } // airfield without ICAO code if (icao.isEmpty()) { continue; } // airfield without ICAO code
if (!CAirportIcaoCode::isValidIcaoDesignator(icao)) { continue; } // tiny airfields/strips in simulator if (!CAirportIcaoCode::isValidIcaoDesignator(icao, true)) { continue; } // tiny airfields/strips in simulator
if (CAirportIcaoCode::containsNumbers(icao)) { continue; } // tiny airfields/strips in simulator if (CAirportIcaoCode::containsNumbers(icao)) { continue; } // tiny airfields/strips in simulator
const CCoordinateGeodetic pos(pFacilityAirport->Latitude, pFacilityAirport->Longitude, pFacilityAirport->Altitude); const CCoordinateGeodetic pos(pFacilityAirport->Latitude, pFacilityAirport->Longitude, pFacilityAirport->Altitude);
const CAirport airport(CAirportIcaoCode(icao), pos); const CAirport airport(CAirportIcaoCode(icao), pos);