From 4149b0a19d39ed034da4db3f7ab18720883b339c Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Sat, 26 Apr 2014 16:05:25 +0200 Subject: [PATCH] refs #195, refs#212, flightplan widget (completely encapsulated) for FP handling --- src/blackgui/blackgui.pro | 13 +- src/blackgui/flightplancomponent.cpp | 314 ++++++++++++ src/blackgui/flightplancomponent.h | 65 +++ src/blackgui/flightplancomponent.ui | 715 +++++++++++++++++++++++++++ 4 files changed, 1100 insertions(+), 7 deletions(-) create mode 100644 src/blackgui/flightplancomponent.cpp create mode 100644 src/blackgui/flightplancomponent.h create mode 100644 src/blackgui/flightplancomponent.ui diff --git a/src/blackgui/blackgui.pro b/src/blackgui/blackgui.pro index a005e6422..76ed6392d 100644 --- a/src/blackgui/blackgui.pro +++ b/src/blackgui/blackgui.pro @@ -8,13 +8,11 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = blackgui TEMPLATE = lib CONFIG += staticlib -CONFIG += blackmisc +CONFIG += blackmisc blacksim blackcore INCLUDEPATH += .. DEPENDPATH += . .. -LIBS += -L../../lib -lblackmisc - # PRECOMPILED_HEADER = stdpch.h precompile_header:!isEmpty(PRECOMPILED_HEADER) { DEFINES += USING_PCH @@ -22,14 +20,15 @@ precompile_header:!isEmpty(PRECOMPILED_HEADER) { DEFINES += LOG_IN_FILE -win32:!win32-g++*: PRE_TARGETDEPS += ../../lib/blackmisc.lib -else: PRE_TARGETDEPS += ../../lib/libblackmisc.a +win32:!win32-g++*: PRE_TARGETDEPS += ../../lib/blackmisc.lib ../../lib/blacksim.lib ../../lib/blackcore.lib +else: PRE_TARGETDEPS += ../../lib/libblackmisc.a ../../lib/libblacksim.a ../../lib/libblackcore.a HEADERS += *.h SOURCES += *.cpp +FORMS += *.ui +RESOURCES += blackgui.qrc + DESTDIR = ../../lib OTHER_FILES += -RESOURCES += blackgui.qrc - include (../../libraries.pri) diff --git a/src/blackgui/flightplancomponent.cpp b/src/blackgui/flightplancomponent.cpp new file mode 100644 index 000000000..f4215d729 --- /dev/null +++ b/src/blackgui/flightplancomponent.cpp @@ -0,0 +1,314 @@ +#include "flightplancomponent.h" +#include "ui_flightplancomponent.h" + +using namespace BlackMisc; +using namespace BlackMisc::Aviation; + +namespace BlackGui +{ + CFlightPlanComponent::CFlightPlanComponent(QWidget *parent) : + QTabWidget(parent), CRuntimeBasedComponent(nullptr, false), ui(new Ui::CFlightPlanComponent) + { + ui->setupUi(this); + connect(this->ui->pb_Send, &QPushButton::pressed, this, &CFlightPlanComponent::sendFlightPlan); + connect(this->ui->pb_Load, &QPushButton::pressed, this, &CFlightPlanComponent::loadFlightPlan); + connect(this->ui->pb_Reset, &QPushButton::pressed, this, &CFlightPlanComponent::resetFlightPlan); + + bool c; + c = connect(this->ui->cb_VoiceCapabilities, SIGNAL(currentIndexChanged(int)), this, SLOT(buildRemarkString())); + Q_ASSERT(c); + c = connect(this->ui->cb_NavigationEquipment, SIGNAL(currentIndexChanged(int)), this, SLOT(buildRemarkString())); + Q_ASSERT(c); + c = connect(this->ui->cb_PerformanceCategory, SIGNAL(currentIndexChanged(int)), this, SLOT(buildRemarkString())); + Q_ASSERT(c); + c = connect(this->ui->cb_PilotRating, SIGNAL(currentIndexChanged(int)), this, SLOT(buildRemarkString())); + Q_ASSERT(c); + c = connect(this->ui->cb_RequiredNavigationPerformance, SIGNAL(currentIndexChanged(int)), this, SLOT(buildRemarkString())); + Q_ASSERT(c); + c = connect(this->ui->cb_NoSidsStarts, SIGNAL(toggled(bool)), this, SLOT(buildRemarkString())); + Q_ASSERT(c); + c = connect(this->ui->le_AircraftRegistration, SIGNAL(textChanged(QString)), this, SLOT(buildRemarkString())); + Q_ASSERT(c); + c = connect(this->ui->le_AirlineOperator, SIGNAL(textChanged(QString)), this, SLOT(buildRemarkString())); + Q_ASSERT(c); + + connect(this->ui->pte_AdditionalRemarks, &QPlainTextEdit::textChanged, this, &CFlightPlanComponent::buildRemarkString); + connect(this->ui->frp_SelcalCode, &CSelcalCodeSelector::valueChanged, this, &CFlightPlanComponent::buildRemarkString); + connect(this->ui->pb_CopyOver, &QPushButton::pressed, this, &CFlightPlanComponent::copyRemarks); + connect(this->ui->pb_RemarksGenerator, &QPushButton::clicked, this, &CFlightPlanComponent::currentTabGenerator); + + this->ui->frp_SelcalCode->resetSelcalCodes(true); + this->resetFlightPlan(); + this->buildRemarkString(); + } + + CFlightPlanComponent::~CFlightPlanComponent() + { + delete ui; + } + + void CFlightPlanComponent::prefillWithAircraftData(const BlackMisc::Aviation::CAircraft &aircraftData) + { + this->ui->le_Callsign->setText(aircraftData.getCallsign().asString()); + this->ui->le_AircraftType->setText(aircraftData.getIcaoInfo().getAircraftDesignator()); + this->ui->le_PilotsName->setText(aircraftData.getPilot().getRealName()); + } + + void CFlightPlanComponent::prefillWithFlightPlanData(const BlackMisc::Aviation::CFlightPlan &flightPlan) + { + this->ui->le_AlternateAirport->setText(flightPlan.getAlternateAirportIcao().asString()); + this->ui->le_DestinationAirport->setText(flightPlan.getAlternateAirportIcao().asString()); + this->ui->le_OriginAirport->setText(flightPlan.getAlternateAirportIcao().asString()); + this->ui->pte_Route->setPlainText(flightPlan.getRoute()); + this->ui->pte_Remarks->setPlainText(flightPlan.getRemarks()); + this->ui->le_TakeOffTimePlanned->setText(flightPlan.getTakeoffTimePlannedHourMin()); + this->ui->le_FuelOnBoard->setText(flightPlan.getFuelTimeHourMin()); + this->ui->le_EstimatedTimeEnroute->setText(flightPlan.getEnrouteTimeHourMin()); + this->ui->le_CrusingAltitude->setText(flightPlan.getCruiseAltitude().toQString()); + this->ui->le_CruiseTrueAirspeed->setText(flightPlan.getCruiseTrueAirspeed().valueRoundedWithUnit(BlackMisc::PhysicalQuantities::CSpeedUnit::kts(), 0)); + } + + BlackMisc::CStatusMessageList CFlightPlanComponent::validateAndInitializeFlightPlan(BlackMisc::Aviation::CFlightPlan &flightPlan) + { + BlackMisc::CStatusMessageList messages; + QString v; + + CFlightPlan::FlightRules rule; + if (this->ui->rb_TypeIfr->isChecked()) + rule = CFlightPlan::IFR; + else if (this->ui->rb_TypeVfr->isChecked()) + rule = CFlightPlan::VFR; + else if (this->ui->rb_TypeSvfr->isChecked()) + rule = CFlightPlan::SVFR; + flightPlan.setFlightRule(rule); + + v = ui->le_Callsign->text().trimmed(); + if (v.isEmpty()) + { + QString m = QString("Missing %1").arg(this->ui->lbl_Callsign->text()); + messages.push_back(CStatusMessage::getValidationError(m)); + } + + v = ui->pte_Route->toPlainText().trimmed(); + if (v.isEmpty()) + { + QString m = QString("Missing %1").arg(this->ui->lbl_Route->text()); + messages.push_back(CStatusMessage::getValidationError(m)); + } + else + flightPlan.setRoute(v); + + v = ui->pte_Remarks->toPlainText().trimmed(); + flightPlan.setRemarks(v); + + v = ui->le_EstimatedTimeEnroute->text(); + if (v.isEmpty() || v == defaultTime()) + { + QString m = QString("Missing %1").arg(this->ui->lbl_EstimatedTimeEnroute->text()); + messages.push_back(CStatusMessage::getValidationError(m)); + } + else + flightPlan.setEnrouteTime(v); + + v = ui->le_FuelOnBoard->text(); + if (v.isEmpty() || v == defaultTime()) + { + QString m = QString("Missing %1").arg(this->ui->lbl_FuelOnBorad->text()); + messages.push_back(CStatusMessage::getValidationError(m)); + } + else + flightPlan.setFuelTime(v); + + v = ui->le_TakeOffTimePlanned->text(); + if (v.isEmpty() || v == defaultTime()) + { + QString m = QString("Missing %1").arg(this->ui->lbl_TakeOffTimePlanned->text()); + messages.push_back(CStatusMessage::getValidationError(m)); + } + else + flightPlan.setTakeoffTimePlanned(v); + + v = ui->le_CrusingAltitude->text().trimmed(); + CAltitude cruisingAltitude(v); + if (v.isEmpty() || cruisingAltitude.isNull()) + { + QString m = QString("Wrong %1").arg(this->ui->lbl_CrusingAltitude->text()); + messages.push_back(CStatusMessage::getValidationError(m)); + } + else + flightPlan.setCruiseAltitude(cruisingAltitude); + + v = this->ui->le_AlternateAirport->text(); + if (v.isEmpty() || v.endsWith(defaultIcao(), Qt::CaseInsensitive)) + { + QString m = QString("Missing %1").arg(this->ui->lbl_AlternateAirport->text()); + messages.push_back(CStatusMessage::getValidationError(m)); + flightPlan.setAlternateAirportIcao(defaultIcao()); + } + else + flightPlan.setAlternateAirportIcao(v); + + v = this->ui->le_DestinationAirport->text(); + if (v.isEmpty() || v.endsWith(defaultIcao(), Qt::CaseInsensitive)) + { + QString m = QString("Missing %1").arg(this->ui->lbl_DestinationAirport->text()); + messages.push_back(CStatusMessage::getValidationError(m)); + flightPlan.setDestinationAirportIcao(defaultIcao()); + } + else + flightPlan.setDestinationAirportIcao(v); + + v = this->ui->le_CruiseTrueAirspeed->text(); + BlackMisc::PhysicalQuantities::CSpeed cruiseTAS; + cruiseTAS.parseFromString(v); + if (cruiseTAS.isNull()) + { + QString m = QString("Wrong TAS, %1").arg(this->ui->lbl_CruiseTrueAirspeed->text()); + messages.push_back(CStatusMessage::getValidationError(m)); + flightPlan.setDestinationAirportIcao(defaultIcao()); + } + else + flightPlan.setCruiseTrueAirspeed(cruiseTAS); + + + v = this->ui->le_OriginAirport->text(); + if (v.isEmpty() || v.endsWith(defaultIcao(), Qt::CaseInsensitive)) + { + QString m = QString("Missing %1").arg(this->ui->lbl_OriginAirport->text()); + messages.push_back(CStatusMessage::getValidationError(m)); + flightPlan.setOriginAirportIcao(defaultIcao()); + } + else + flightPlan.setOriginAirportIcao(v); + + return messages; + } + + void CFlightPlanComponent::sendFlightPlan() + { + CFlightPlan flightPlan; + CStatusMessageList messages = this->validateAndInitializeFlightPlan(flightPlan); + if (messages.isEmpty()) + { + // no error, send if possible + if (this->getIContextNetwork()->isConnected()) + this->getIContextNetwork()->sendFlightPlan(flightPlan); + else + { + CStatusMessage m = CStatusMessage::getErrorMessage("No errors, but not connected, cannot send flight plan", CStatusMessage::TypeTrafficNetwork); + this->getIContextApplication()->sendStatusMessage(m); + } + } + else + { + this->getIContextApplication()->sendStatusMessages(messages); + } + } + + void CFlightPlanComponent::resetFlightPlan() + { + if (this->getIContextNetwork()) + { + this->prefillWithAircraftData(this->getIContextNetwork()->getOwnAircraft()); + } + this->ui->le_AircraftRegistration->clear(); + this->ui->le_AirlineOperator->clear(); + this->ui->le_CrusingAltitude->setText("FL70"); + this->ui->le_CruiseTrueAirspeed->setText("100 kts"); + this->ui->pte_Remarks->clear(); + this->ui->pte_Route->clear(); + this->ui->le_AlternateAirport->setText(defaultIcao()); + this->ui->le_DestinationAirport->setText(defaultIcao()); + this->ui->le_OriginAirport->setText(defaultIcao()); + this->ui->le_FuelOnBoard->setText(defaultTime()); + this->ui->le_EstimatedTimeEnroute->setText(defaultTime()); + this->ui->le_TakeOffTimePlanned->setText(QDateTime::currentDateTimeUtc().addSecs(30 * 60).toString("hh:mm")); + } + + void CFlightPlanComponent::loadFlightPlan() + { + + } + + void CFlightPlanComponent::buildRemarkString() + { + QString rem; + QString v = this->ui->cb_VoiceCapabilities->currentText().toUpper(); + if (v.contains("TEXT")) + rem.append("/T/ "); + else if (v.contains("VOICE")) + rem.append("/V/ "); + else if (v.contains("RECEIVE")) + rem.append("/R/ "); + + v = this->ui->le_AirlineOperator->text().trimmed(); + if (!v.isEmpty()) rem.append("OPR/").append(v).append(" "); + + v = this->ui->le_AircraftRegistration->text().trimmed(); + if (!v.isEmpty()) rem.append("REG/").append(v).append(" "); + + v = this->ui->cb_PilotRating->currentText().toUpper(); + if (v.contains("P1")) + rem.append("PR/P1 "); + else if (v.contains("P2")) + rem.append("PR/P2 "); + else if (v.contains("P3")) + rem.append("PR/P3 "); + else if (v.contains("P4")) + rem.append("PR/P4 "); + else if (v.contains("P5")) + rem.append("PR/P5 "); + + v = this->ui->cb_RequiredNavigationPerformance->currentText().toUpper(); + if (v.contains("10")) + rem.append("RNP10 "); + else if (v.contains("4")) + rem.append("RNP4 "); + + v = this->ui->cb_NavigationEquipment->currentText().toUpper(); + if (v.contains("VORS")) + rem.append("NAV/VORNDB "); + else if (v.contains("SIDS")) + rem.append("NAV/GPSRNAV "); + if (v.contains("DEFAULT")) + rem.append("NAV/GPS "); + else if (v.contains("OCEANIC")) + rem.append("NAV/GPSOCEANIC "); + + v = this->ui->cb_PerformanceCategory->currentText().toUpper(); + if (v.startsWith("A")) + rem.append("PER/A "); + else if (v.startsWith("B")) + rem.append("PER/B "); + else if (v.startsWith("C")) + rem.append("PER/C "); + else if (v.startsWith("D")) + rem.append("PER/D "); + + if (this->ui->frp_SelcalCode->hasValidCode()) + { + rem.append("SEL/").append(this->ui->frp_SelcalCode->getSelcalCode()); + rem.append(" "); + } + + if (this->ui->cb_NoSidsStarts->isChecked()) + rem.append("NO SID/STAR "); + + v = this->ui->pte_AdditionalRemarks->toPlainText().trimmed(); + if (!v.isEmpty()) rem.append(v); + + rem = rem.simplified().trimmed(); + this->ui->pte_RemarksGenerated->setPlainText(rem); + } + + void CFlightPlanComponent::copyRemarks() + { + this->ui->pte_Remarks->setPlainText(this->ui->pte_RemarksGenerated->toPlainText()); + this->getIContextApplication()->sendStatusMessage(CStatusMessage::getInfoMessage("Copied remarks", CStatusMessage::TypeTrafficNetwork)); + } + + void CFlightPlanComponent::currentTabGenerator() + { + this->setCurrentWidget(this->ui->tb_RemarksGenerator); + } +} diff --git a/src/blackgui/flightplancomponent.h b/src/blackgui/flightplancomponent.h new file mode 100644 index 000000000..f162954ae --- /dev/null +++ b/src/blackgui/flightplancomponent.h @@ -0,0 +1,65 @@ +#ifndef BLACKGUI_FLIGHTPLANCOMPONENT_H +#define BLACKGUI_FLIGHTPLANCOMPONENT_H + +#include "blackgui/runtimebasedcomponent.h" +#include "blackmisc/avaircraft.h" +#include "blackmisc/avflightplan.h" + +#include + +namespace Ui { class CFlightPlanComponent; } +namespace BlackGui +{ + //! Flight plan widget + class CFlightPlanComponent : public QTabWidget, public CRuntimeBasedComponent + { + Q_OBJECT + + public: + //! Constructor + explicit CFlightPlanComponent(QWidget *parent = nullptr); + + //! Destructor + ~CFlightPlanComponent(); + + public slots: + //! Prefill with aircraft data + void prefillWithAircraftData(const BlackMisc::Aviation::CAircraft &aircraftData); + + //! Prefill with aircraft dara + void prefillWithFlightPlanData(const BlackMisc::Aviation::CFlightPlan &flightPlan); + + private: + Ui::CFlightPlanComponent *ui; + + //! Validate, generates status messages + BlackMisc::CStatusMessageList validateAndInitializeFlightPlan(BlackMisc::Aviation::CFlightPlan &fligtPlan); + + //! Default value for airport ICAO airports + static const QString &defaultIcao() { static QString d("ICAO"); return d; } + + //! Default value for time + static const QString &defaultTime() { static QString t("00:00"); return t; } + + private slots: + //! Send flightplan + void sendFlightPlan(); + + //! Reset Flightplan + void resetFlightPlan(); + + //! Load Flightplan + void loadFlightPlan(); + + //! Remark + void buildRemarkString(); + + //! Copy over + void copyRemarks(); + + //! Show generator tab page + void currentTabGenerator(); + + }; +} +#endif // guard diff --git a/src/blackgui/flightplancomponent.ui b/src/blackgui/flightplancomponent.ui new file mode 100644 index 000000000..2853b0fcf --- /dev/null +++ b/src/blackgui/flightplancomponent.ui @@ -0,0 +1,715 @@ + + + CFlightPlanComponent + + + + 0 + 0 + 555 + 477 + + + + TabWidget + + + 0 + + + + Flight plan + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + + 99:99 + + + 00:00 + + + + + + + 3. Aircraft type + + + false + + + true + + + + + + + 0 kts + + + 40 + + + + + + + 1. Type + + + + + + VFR + + + + + + + SVFR + + + + + + + IFR + + + true + + + + + + + + + + 10. Estimated time enroute + + + true + + + + + + + 5. Departure airport + + + true + + + + + + + Send plan + + + + + + + 7. Cruising altitude + + + true + + + + + + + + + + + + + + + + 40 + + + true + + + + + + + + + + 99:99 + + + 00:00 + + + 5 + + + + + + + >AAAA + + + ICAO + + + + + + + 6. Departure time + + + true + + + + + + + + + + true + + + + + + + 14. Pilots name / homebase + + + true + + + + + + + 40 + + + + + + + 9.Destination airport + + + true + + + + + + + 2. Callsign + + + false + + + true + + + + + + + 4. True airspeed + + + true + + + + + + + 8. Route + + + + + + + 13. Alternate airport + + + true + + + + + + + 12. Fuel on board + + + true + + + + + + + >AAAA + + + ICAO + + + + + + + >AAAA + + + ICAO + + + 4 + + + + + + + + + + 99:99 + + + 00:00 + + + 5 + + + + + + + + + 11. Remarks + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + QPushButton { + background-color: transparent; + border: none; + text-align: left; + text-decoration: underline; +} + + + Qt::ImhNone + + + Generator + + + + + + + + + Reset plan + + + + + + + Load plan + + + + + + + + + + Remarks + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + Parse + + + + + + + Copy over + + + + + + + + + + Remarks + + + + + + + Required Navigation Performance + + + true + + + + + + + true + + + + + + + + + + + P0 - unrated + + + + + P1 + + + + + P2 + + + + + P3 + + + + + P4 + + + + + P5 + + + + + + + + Performance category + + + true + + + + + + + + VFR - not required + + + + + 10 miles radius + + + + + 4 miles radius + + + + + + + + Aircraft registration + + + false + + + + + + + Airline operator + + + true + + + + + + + Pilot rating + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + Navigation equipment + + + true + + + + + + + + + + + Full voice + + + + + Text only + + + + + Receive voice + + + + + + + + + + + SELCAL + + + + + + + Final Approach Speed + + + + VFR - not required + + + + + A: below 91kts + + + + + B: 92-121kts + + + + + C: 122-142kts + + + + + D: 143kts or above + + + + + + + + How will you be navigating? + + + + VFR flying visually + + + + + Direct VORs and NDBs + + + + + Default GPS + + + + + GPS or FMC capable of SIDs/STARs + + + + + GPS oceantic certified + + + + + + + + Additional remarks + + + false + + + + + + + Voice capabilities + + + true + + + + + + + no SIDs / STARs + + + + + + + SIDs / STARs + + + + + + + + + + + BlackGui::CSelcalCodeSelector + QFrame +
blackgui/selcalcodeselector.h
+ 1 +
+
+ + +