From 2da12e2dd8875a0fb3d7d100a76f33a1a24f6a99 Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Wed, 31 Jan 2018 23:25:50 +0100 Subject: [PATCH] Ref T226, airport completer * a bigger one with name * same as dialog * smaller one, using the dialog --- src/blackgui/components/airportcompleter.cpp | 135 +++++++++++++++++ src/blackgui/components/airportcompleter.h | 74 +++++++++ src/blackgui/components/airportcompleter.ui | 59 ++++++++ src/blackgui/components/airportdialog.cpp | 36 +++++ src/blackgui/components/airportdialog.h | 51 +++++++ src/blackgui/components/airportdialog.ui | 75 +++++++++ .../components/airportsmallcompleter.cpp | 143 ++++++++++++++++++ .../components/airportsmallcompleter.h | 83 ++++++++++ .../components/airportsmallcompleter.ui | 53 +++++++ src/blackmisc/aviation/airport.cpp | 5 + src/blackmisc/aviation/airport.h | 3 + src/blackmisc/aviation/airportlist.cpp | 35 ++++- src/blackmisc/aviation/airportlist.h | 6 + 13 files changed, 750 insertions(+), 8 deletions(-) create mode 100644 src/blackgui/components/airportcompleter.cpp create mode 100644 src/blackgui/components/airportcompleter.h create mode 100644 src/blackgui/components/airportcompleter.ui create mode 100644 src/blackgui/components/airportdialog.cpp create mode 100644 src/blackgui/components/airportdialog.h create mode 100644 src/blackgui/components/airportdialog.ui create mode 100644 src/blackgui/components/airportsmallcompleter.cpp create mode 100644 src/blackgui/components/airportsmallcompleter.h create mode 100644 src/blackgui/components/airportsmallcompleter.ui diff --git a/src/blackgui/components/airportcompleter.cpp b/src/blackgui/components/airportcompleter.cpp new file mode 100644 index 000000000..4867189af --- /dev/null +++ b/src/blackgui/components/airportcompleter.cpp @@ -0,0 +1,135 @@ +/* Copyright (C) 2018 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "airportcompleter.h" +#include "ui_airportcompleter.h" +#include "blackgui/guiapplication.h" +#include "blackgui/uppercasevalidator.h" +#include "blackcore/webdataservices.h" +#include "blackmisc/aviation/airportlist.h" +#include + +using namespace BlackCore; +using namespace BlackMisc::Aviation; + +namespace BlackGui +{ + namespace Components + { + CAirportCompleter::CAirportCompleter(QWidget *parent) : + QFrame(parent), + ui(new Ui::CAirportCompleter) + { + ui->setupUi(this); + ui->le_Icao->setValidator(new CUpperCaseValidator(ui->le_Icao)); + + connect(sGui->getWebDataServices(), &CWebDataServices::swiftDbAllDataRead, this, &CAirportCompleter::onAirportsChanged); + connect(ui->le_Icao, &QLineEdit::editingFinished, this, &CAirportCompleter::onIcaoChanged); + connect(ui->le_Name, &QLineEdit::editingFinished, this, &CAirportCompleter::onNameChanged); + connect(ui->le_Location, &QLineEdit::editingFinished, this, &CAirportCompleter::onLocationChanged); + this->onAirportsChanged(); + } + + CAirportCompleter::~CAirportCompleter() + { } + + void CAirportCompleter::setAirport(const CAirport &airport) + { + if (m_current == airport) { return; } + m_current = airport; + if (airport.getIcaoAsString() != ui->le_Icao->text()) { ui->le_Icao->setText(airport.getIcaoAsString()); } + if (airport.getDescriptiveName() != ui->le_Name->text()) { ui->le_Name->setText(airport.getDescriptiveName()); } + if (airport.getLocation() != ui->le_Location->text()) { ui->le_Location->setText(airport.getLocation()); } + emit this->changedAirport(m_current); + } + + QString CAirportCompleter::getIcaoText() const + { + return ui->le_Icao->text().trimmed().toUpper(); + } + + void CAirportCompleter::setReadOnly(bool readOnly) + { + ui->le_Icao->setReadOnly(readOnly); + ui->le_Location->setReadOnly(readOnly); + ui->le_Name->setReadOnly(readOnly); + } + + void CAirportCompleter::clear() + { + m_current = CAirport(); + ui->le_Icao->clear(); + ui->le_Location->clear(); + ui->le_Name->clear(); + } + + void CAirportCompleter::onIcaoChanged() + { + const QString icao(this->getIcaoText()); + if (m_current.getIcaoAsString() == icao) { return; } + const CAirport airport(sGui->getWebDataServices()->getAirportForIcaoDesignator(icao)); + this->setAirport(airport); + } + + void CAirportCompleter::onNameChanged() + { + const QString name(ui->le_Name->text()); + if (m_current.getDescriptiveName() == name) { return; } + const CAirport airport(sGui->getWebDataServices()->getAirportForNameOrLocation(name)); + this->setAirport(airport); + } + + void CAirportCompleter::onLocationChanged() + { + const QString location(ui->le_Location->text()); + if (m_current.getLocation() == location) { return; } + const CAirport airport(sGui->getWebDataServices()->getAirportForNameOrLocation(location)); + this->setAirport(airport); + } + + void CAirportCompleter::onAirportsChanged() + { + if (!sGui && !sGui->hasWebDataServices()) { return; } + const CAirportList airports = sGui->getWebDataServices()->getAirports(); + ui->le_Icao->setCompleter(new QCompleter(airports.allIcaoCodes(true), ui->le_Icao)); + ui->le_Name->setCompleter(new QCompleter(airports.allDescriptivesNames(true), ui->le_Name)); + ui->le_Location->setCompleter(new QCompleter(airports.allLocations(true), ui->le_Location)); + + if (ui->le_Icao->completer()->popup()) + { + ui->le_Icao->completer()->setCaseSensitivity(Qt::CaseInsensitive); + ui->le_Icao->completer()->popup()->setObjectName("AirportCompleter.Icao"); + ui->le_Icao->completer()->popup()->setMinimumWidth(75); + } + if (ui->le_Name->completer()->popup()) + { + ui->le_Name->completer()->setCaseSensitivity(Qt::CaseInsensitive); + ui->le_Name->completer()->popup()->setObjectName("AirportCompleter.Name"); + ui->le_Name->completer()->popup()->setMinimumWidth(150); + } + if (ui->le_Location->completer()->popup()) + { + ui->le_Location->completer()->setCaseSensitivity(Qt::CaseInsensitive); + ui->le_Location->completer()->popup()->setObjectName("AirportCompleter.Location"); + ui->le_Location->completer()->popup()->setMinimumWidth(150); + } + + // turn into airport when it was not possible before + if (m_current.isNull()) + { + const QString icao = this->getIcaoText(); + if (CAirportIcaoCode::isValidIcaoDesignator(icao)) + { + const CAirport airport = sGui->getWebDataServices()->getAirportForIcaoDesignator(icao); + if (!airport.isNull()) { this->setAirport(airport); } + } + } + } + } // ns +} // ns diff --git a/src/blackgui/components/airportcompleter.h b/src/blackgui/components/airportcompleter.h new file mode 100644 index 000000000..7729a23be --- /dev/null +++ b/src/blackgui/components/airportcompleter.h @@ -0,0 +1,74 @@ +/* Copyright (C) 2018 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKGUI_COMPONENTS_AIRPORTCOMPLETER_H +#define BLACKGUI_COMPONENTS_AIRPORTCOMPLETER_H + +#include "blackmisc/aviation/airport.h" +#include +#include + +namespace Ui { class CAirportCompleter; } +namespace BlackGui +{ + namespace Components + { + //! Airport completer, UI element so select by ICAO, name or location + class CAirportCompleter : public QFrame + { + Q_OBJECT + + public: + //! Get the correct airport + explicit CAirportCompleter(QWidget *parent = nullptr); + + //! Destructor + virtual ~CAirportCompleter(); + + //! Set airport + void setAirport(const BlackMisc::Aviation::CAirport &airport); + + //! Get airport + const BlackMisc::Aviation::CAirport &getAirport() const { return m_current; } + + //! The raw ICAO code text + QString getIcaoText() const; + + //! Read only + void setReadOnly(bool readOnly); + + //! Clear the form + void clear(); + + signals: + //! Airport has been changed + void changedAirport(const BlackMisc::Aviation::CAirport &airport); + + private: + //! ICAO code has been changed in UI + void onIcaoChanged(); + + //! Name has been changed in UI + void onNameChanged(); + + //! Location has been changed in UI + void onLocationChanged(); + + //! Airports backend data changed + void onAirportsChanged(); + + QScopedPointer ui; + BlackMisc::Aviation::CAirport m_current; //!< current airport + }; + } // ns +} // ns + +#endif // guard diff --git a/src/blackgui/components/airportcompleter.ui b/src/blackgui/components/airportcompleter.ui new file mode 100644 index 000000000..7bf7ae218 --- /dev/null +++ b/src/blackgui/components/airportcompleter.ui @@ -0,0 +1,59 @@ + + + CAirportCompleter + + + + 0 + 0 + 232 + 22 + + + + Airport completer + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + ICAO + + + + + + + name + + + + + + + location + + + + + + + le_Icao + le_Name + le_Location + + + + diff --git a/src/blackgui/components/airportdialog.cpp b/src/blackgui/components/airportdialog.cpp new file mode 100644 index 000000000..a6880e756 --- /dev/null +++ b/src/blackgui/components/airportdialog.cpp @@ -0,0 +1,36 @@ +#include "airportdialog.h" +#include "ui_airportdialog.h" + +using namespace BlackMisc::Aviation; + +namespace BlackGui +{ + namespace Components + { + CAirportDialog::CAirportDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::CAirportDialog) + { + ui->setupUi(this); + this->setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint); + } + + CAirportDialog::~CAirportDialog() + { } + + void CAirportDialog::setAirport(const CAirport &airport) + { + ui->comp_AirportCompleter->setAirport(airport); + } + + CAirport CAirportDialog::getAirport() const + { + return ui->comp_AirportCompleter->getAirport(); + } + + void CAirportDialog::clear() + { + ui->comp_AirportCompleter->clear(); + } + } // ns +} // ns diff --git a/src/blackgui/components/airportdialog.h b/src/blackgui/components/airportdialog.h new file mode 100644 index 000000000..87ba9ac5f --- /dev/null +++ b/src/blackgui/components/airportdialog.h @@ -0,0 +1,51 @@ +/* Copyright (C) 2018 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKGUI_COMPONENTS_AIRPORTDIALOG_H +#define BLACKGUI_COMPONENTS_AIRPORTDIALOG_H + +#include "blackmisc/aviation/airport.h" +#include +#include + +namespace Ui { class CAirportDialog; } +namespace BlackGui +{ + namespace Components + { + //! Dialog for finding an airport + class CAirportDialog : public QDialog + { + Q_OBJECT + + public: + //! Constructor + explicit CAirportDialog(QWidget *parent = nullptr); + + //! Destructor + virtual ~CAirportDialog(); + + //! Set airport + void setAirport(const BlackMisc::Aviation::CAirport &airport); + + //! Get airport + BlackMisc::Aviation::CAirport getAirport() const; + + //! Clear the form + void clear(); + + private: + QScopedPointer ui; + }; + } // ns +} // ns + +#endif // guard diff --git a/src/blackgui/components/airportdialog.ui b/src/blackgui/components/airportdialog.ui new file mode 100644 index 000000000..de1f97e2f --- /dev/null +++ b/src/blackgui/components/airportdialog.ui @@ -0,0 +1,75 @@ + + + CAirportDialog + + + + 0 + 0 + 300 + 90 + + + + Select an airport + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + BlackGui::Components::CAirportCompleter + QFrame +
blackgui/components/airportcompleter.h
+ 1 +
+
+ + + + bb_AirportDialog + accepted() + CAirportDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + bb_AirportDialog + rejected() + CAirportDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/src/blackgui/components/airportsmallcompleter.cpp b/src/blackgui/components/airportsmallcompleter.cpp new file mode 100644 index 000000000..6cc08f303 --- /dev/null +++ b/src/blackgui/components/airportsmallcompleter.cpp @@ -0,0 +1,143 @@ +/* Copyright (C) 2018 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "airportsmallcompleter.h" +#include "ui_airportsmallcompleter.h" +#include "airportdialog.h" +#include "blackgui/guiapplication.h" +#include "blackgui/guiutility.h" +#include "blackgui/uppercasevalidator.h" +#include "blackcore/webdataservices.h" +#include "blackmisc/aviation/airportlist.h" +#include + +using namespace BlackCore; +using namespace BlackMisc::Aviation; + +namespace BlackGui +{ + namespace Components + { + CAirportSmallCompleter::CAirportSmallCompleter(QWidget *parent) : + QFrame(parent), + ui(new Ui::CAirportSmallCompleter) + { + ui->setupUi(this); + ui->le_Icao->setValidator(new CUpperCaseValidator(ui->le_Icao)); + + connect(sGui->getWebDataServices(), &CWebDataServices::swiftDbAllDataRead, this, &CAirportSmallCompleter::onAirportsChanged); + connect(ui->le_Icao, &QLineEdit::editingFinished, this, &CAirportSmallCompleter::onIcaoChanged); + connect(ui->le_Icao, &QLineEdit::editingFinished, this, &CAirportSmallCompleter::editingFinished); + connect(ui->tb_Dialog, &QToolButton::clicked, this, &CAirportSmallCompleter::showAirportsDialog); + this->onAirportsChanged(); + } + + CAirportSmallCompleter::~CAirportSmallCompleter() + { } + + void CAirportSmallCompleter::setAirport(const CAirport &airport) + { + if (m_current == airport) { return; } + m_current = airport; + if (airport.getIcaoAsString() != ui->le_Icao->text()) { ui->le_Icao->setText(airport.getIcaoAsString()); } + emit this->changedAirport(m_current); + } + + void CAirportSmallCompleter::setAirportIcaoCode(const CAirportIcaoCode &airportCode) + { + if (sGui && sGui->hasWebDataServices()) + { + const CAirport airport = sGui->getWebDataServices()->getAirportForIcaoDesignator(airportCode.asString()); + if (!airport.isNull()) + { + this->setAirport(airport); + return; + } + } + if (ui->le_Icao->text() != airportCode.asString()) + { + ui->le_Icao->setText(airportCode.asString()); + } + } + + CAirportIcaoCode CAirportSmallCompleter::getAirportIcaoCode() const + { + if (m_current.hasValidIcaoCode()) { return m_current.getIcao(); } + return CAirportIcaoCode(this->getIcaoText()); + } + + QString CAirportSmallCompleter::getIcaoText() const + { + return ui->le_Icao->text().trimmed().toUpper(); + } + + void CAirportSmallCompleter::setReadOnly(bool readOnly) + { + ui->le_Icao->setReadOnly(readOnly); + ui->tb_Dialog->setEnabled(!readOnly); + } + + void CAirportSmallCompleter::clear() + { + ui->le_Icao->clear(); + this->m_current = CAirport(); + } + + void CAirportSmallCompleter::onIcaoChanged() + { + if (!sGui && !sGui->hasWebDataServices()) { return; } + const CAirport airport = sGui->getWebDataServices()->getAirportForIcaoDesignator(this->getIcaoText()); + if (!airport.isNull()) + { + this->setAirport(airport); + } + } + + void CAirportSmallCompleter::onAirportsChanged() + { + if (!sGui && !sGui->hasWebDataServices()) { return; } + const CAirportList airports = sGui->getWebDataServices()->getAirports(); + ui->le_Icao->setCompleter(new QCompleter(airports.allIcaoCodes(true), ui->le_Icao)); + + if (ui->le_Icao->completer()->popup()) + { + ui->le_Icao->completer()->popup()->setObjectName("AirportSmallCompleter.ICAO"); + ui->le_Icao->completer()->popup()->setMinimumWidth(75); + ui->le_Icao->completer()->setCaseSensitivity(Qt::CaseInsensitive); + } + + // turn into airport when it was not possible before + if (m_current.isNull()) + { + const QString icao = this->getIcaoText(); + if (CAirportIcaoCode::isValidIcaoDesignator(icao)) + { + const CAirport airport = sGui->getWebDataServices()->getAirportForIcaoDesignator(icao); + if (!airport.isNull()) { this->setAirport(airport); } + } + } + } + + void CAirportSmallCompleter::showAirportsDialog() + { + if (!m_airportsDialog) + { + m_airportsDialog.reset(new CAirportDialog(this)); + m_airportsDialog->setModal(true); + } + m_airportsDialog->setAirport(this->getAirport()); + const int rv = m_airportsDialog->exec(); + if (rv != QDialog::Accepted) { return; } + + const CAirport airport = m_airportsDialog->getAirport(); + if (airport.isNull()) { return; } + this->setAirport(airport); + } + } // ns +} // ns diff --git a/src/blackgui/components/airportsmallcompleter.h b/src/blackgui/components/airportsmallcompleter.h new file mode 100644 index 000000000..29681d5ef --- /dev/null +++ b/src/blackgui/components/airportsmallcompleter.h @@ -0,0 +1,83 @@ +/* Copyright (C) 2018 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKGUI_COMPONENTS_AIRPORTSMALLCOMPLETER_H +#define BLACKGUI_COMPONENTS_AIRPORTSMALLCOMPLETER_H + +#include "blackmisc/aviation/airport.h" +#include +#include + +namespace Ui { class CAirportSmallCompleter; } +namespace BlackGui +{ + namespace Components + { + class CAirportDialog; + + //! Smaller version of CAirportCompleter, using a CAirportDialog + class CAirportSmallCompleter : public QFrame + { + Q_OBJECT + + public: + //! Constructor + explicit CAirportSmallCompleter(QWidget *parent = nullptr); + + //! Destructor + virtual ~CAirportSmallCompleter(); + + //! Set airport + void setAirport(const BlackMisc::Aviation::CAirport &airport); + + //! Set airport + void setAirportIcaoCode(const BlackMisc::Aviation::CAirportIcaoCode &airportCode); + + //! Get airport + const BlackMisc::Aviation::CAirport &getAirport() const { return m_current; } + + //! Get airport ICAO code + BlackMisc::Aviation::CAirportIcaoCode getAirportIcaoCode() const; + + //! The raw ICAO code text + QString getIcaoText() const; + + //! Read only + void setReadOnly(bool readOnly); + + //! Clear + void clear(); + + signals: + //! Airport has been changed + void changedAirport(const BlackMisc::Aviation::CAirport &airport); + + //! \copydoc QLineEdit::editingFinished + void editingFinished(); + + private: + //! ICAO code has been changed in UI + void onIcaoChanged(); + + //! Airports backend data changed + void onAirportsChanged(); + + //! Display dialog + void showAirportsDialog(); + + QScopedPointer ui; + QScopedPointer m_airportsDialog; //!< UI completer + BlackMisc::Aviation::CAirport m_current; //!< this airport + }; + } // ns +} // ns + +#endif // guard diff --git a/src/blackgui/components/airportsmallcompleter.ui b/src/blackgui/components/airportsmallcompleter.ui new file mode 100644 index 000000000..10a7b98ac --- /dev/null +++ b/src/blackgui/components/airportsmallcompleter.ui @@ -0,0 +1,53 @@ + + + CAirportSmallCompleter + + + + 0 + 0 + 102 + 22 + + + + Airport selector + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + ... + + + + :/diagona/icons/diagona/icons/binocular.png:/diagona/icons/diagona/icons/binocular.png + + + + + + + le_Icao + tb_Dialog + + + + + + diff --git a/src/blackmisc/aviation/airport.cpp b/src/blackmisc/aviation/airport.cpp index 0f55152ba..0b387546c 100644 --- a/src/blackmisc/aviation/airport.cpp +++ b/src/blackmisc/aviation/airport.cpp @@ -58,6 +58,11 @@ namespace BlackMisc if (this->m_descriptiveName.isEmpty()) { this->m_descriptiveName = airport.getDescriptiveName(); } } + bool CAirport::isNull() const + { + return (m_icao.isEmpty() && m_descriptiveName.isEmpty()); + } + QString CAirport::convertToQString(bool i18n) const { QString s = i18n ? QCoreApplication::translate("Aviation", "Airport") : "Airport"; diff --git a/src/blackmisc/aviation/airport.h b/src/blackmisc/aviation/airport.h index 2e1c18c93..74fdf44b0 100644 --- a/src/blackmisc/aviation/airport.h +++ b/src/blackmisc/aviation/airport.h @@ -127,6 +127,9 @@ namespace BlackMisc //! Valid ICAO code bool hasValidIcaoCode() const { return !this->getIcao().isEmpty(); } + //! NULL airport? + virtual bool isNull() const override; + //! \copydoc Geo::ICoordinateGeodetic::latitude virtual BlackMisc::Geo::CLatitude latitude() const override { diff --git a/src/blackmisc/aviation/airportlist.cpp b/src/blackmisc/aviation/airportlist.cpp index ac39402c2..a235a3626 100644 --- a/src/blackmisc/aviation/airportlist.cpp +++ b/src/blackmisc/aviation/airportlist.cpp @@ -83,18 +83,37 @@ namespace BlackMisc QStringList icaos; for (const CAirport &airport : *this) { - if (!airport.getIcaoAsString().isEmpty()) - { - icaos.push_back(airport.getIcaoAsString()); - } - } - if (sorted) - { - icaos.sort(); + if (airport.getIcaoAsString().isEmpty()) { continue; } + icaos.push_back(airport.getIcaoAsString()); } + if (sorted) { icaos.sort(); } return icaos; } + QStringList CAirportList::allDescriptivesNames(bool sorted) const + { + QStringList names; + for (const CAirport &airport : *this) + { + if (airport.getDescriptiveName().isEmpty()) { continue; } + names.push_back(airport.getDescriptiveName()); + } + if (sorted) { names.sort(); } + return names; + } + + QStringList CAirportList::allLocations(bool sorted) const + { + QStringList locations; + for (const CAirport &airport : *this) + { + if (airport.getLocation().isEmpty()) { continue; } + locations.push_back(airport.getLocation()); + } + if (sorted) { locations.sort(); } + return locations; + } + CAirportList CAirportList::fromDatabaseJson(const QJsonArray &array, CAirportList *inconsistent) { CAirportList airports; diff --git a/src/blackmisc/aviation/airportlist.h b/src/blackmisc/aviation/airportlist.h index 117e1b7fd..a89d2344f 100644 --- a/src/blackmisc/aviation/airportlist.h +++ b/src/blackmisc/aviation/airportlist.h @@ -64,6 +64,12 @@ namespace BlackMisc //! All ICAO codes QStringList allIcaoCodes(bool sorted) const; + //! All names + QStringList allDescriptivesNames(bool sorted) const; + + //! All names + QStringList allLocations(bool sorted) const; + //! From our DB JSON static CAirportList fromDatabaseJson(const QJsonArray &array, CAirportList *inconsistent = nullptr); };