Files
pilotclient/src/blackgui/components/flightplancomponent.cpp
Klaus Basan 6ca0d480d3 refs #452 adjusted GUI components to
* changed classes (e.g. CAircraft -> CSimulatedAircraft)
* changes signatures in contexts / providers
* minor fixes as renamed GUI widgets, asserts, paint event
2015-11-19 20:59:35 +00:00

429 lines
19 KiB
C++

/* Copyright (C) 2013
* 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 "flightplancomponent.h"
#include "../stylesheetutility.h"
#include "ui_flightplancomponent.h"
#include "blackmisc/logmessage.h"
#include "blackcore/context_network.h"
#include "blackcore/context_ownaircraft.h"
using namespace BlackMisc;
using namespace BlackMisc::Aviation;
using namespace BlackMisc::Simulation;
using namespace BlackMisc::PhysicalQuantities;
using namespace BlackGui;
namespace BlackGui
{
namespace Components
{
CFlightPlanComponent::CFlightPlanComponent(QWidget *parent) :
QTabWidget(parent),
ui(new Ui::CFlightPlanComponent)
{
ui->setupUi(this);
// fix style
this->tabBar()->setExpanding(false);
// connect
connect(this->ui->pb_Send, &QPushButton::pressed, this, &CFlightPlanComponent::ps_sendFlightPlan);
connect(this->ui->pb_Load, &QPushButton::pressed, this, &CFlightPlanComponent::ps_loadFlightPlanFromNetwork);
connect(this->ui->pb_Reset, &QPushButton::pressed, this, &CFlightPlanComponent::ps_resetFlightPlan);
connect(this->ui->pb_ValidateFlightPlan, &QPushButton::pressed, this, &CFlightPlanComponent::ps_validateFlightPlan);
connect(this->ui->cb_VoiceCapabilities, &QComboBox::currentTextChanged, this, &CFlightPlanComponent::ps_currentTextChangedToBuildRemarks);
connect(this->ui->cb_NavigationEquipment, &QComboBox::currentTextChanged, this, &CFlightPlanComponent::ps_currentTextChangedToBuildRemarks);
connect(this->ui->cb_PerformanceCategory, &QComboBox::currentTextChanged, this, &CFlightPlanComponent::ps_currentTextChangedToBuildRemarks);
connect(this->ui->cb_PilotRating, &QComboBox::currentTextChanged, this, &CFlightPlanComponent::ps_currentTextChangedToBuildRemarks);
connect(this->ui->cb_RequiredNavigationPerformance, &QComboBox::currentTextChanged, this, &CFlightPlanComponent::ps_currentTextChangedToBuildRemarks);
bool c = connect(this->ui->le_AircraftRegistration, SIGNAL(textChanged(QString)), this, SLOT(ps_buildRemarksString()));
Q_ASSERT(c);
c = connect(this->ui->cb_NoSidsStarts, SIGNAL(toggled(bool)), this, SLOT(ps_buildRemarksString()));
Q_ASSERT(c);
c = connect(this->ui->le_AirlineOperator, SIGNAL(textChanged(QString)), this, SLOT(ps_buildRemarksString()));
Q_ASSERT(c);
Q_UNUSED(c);
connect(this->ui->pte_AdditionalRemarks, &QPlainTextEdit::textChanged, this, &CFlightPlanComponent::ps_buildRemarksString);
connect(this->ui->frp_SelcalCode, &CSelcalCodeSelector::valueChanged, this, &CFlightPlanComponent::ps_buildRemarksString);
connect(this->ui->frp_SelcalCode, &CSelcalCodeSelector::valueChanged, this, &CFlightPlanComponent::ps_setSelcalInOwnAircraft);
connect(this->ui->pb_CopyOver, &QPushButton::pressed, this, &CFlightPlanComponent::ps_copyRemarks);
connect(this->ui->pb_RemarksGenerator, &QPushButton::clicked, this, &CFlightPlanComponent::ps_currentTabGenerator);
}
CFlightPlanComponent::~CFlightPlanComponent()
{ }
void CFlightPlanComponent::loginDataSet()
{
if (this->m_flightPlan.wasSentOrLoaded()) { return; } // when loaded or sent do not override
if (!this->getIContextOwnAircraft()) { return; }
this->prefillWithAircraftData(this->getIContextOwnAircraft()->getOwnAircraft());
}
void CFlightPlanComponent::prefillWithAircraftData(const BlackMisc::Simulation::CSimulatedAircraft &ownAircraft)
{
// only override with valid values
if (CCallsign::isValidCallsign(ownAircraft.getCallsignAsString()))
{
this->ui->le_Callsign->setText(ownAircraft.getCallsign().asString());
}
if (CAircraftIcaoCode::isValidDesignator(ownAircraft.getAircraftIcaoCodeDesignator()))
{
this->ui->le_AircraftType->setText(ownAircraft.getAircraftIcaoCodeDesignator());
}
if (ownAircraft.hasValidRealName())
{
this->ui->le_PilotsName->setText(ownAircraft.getPilot().getRealName());
}
}
void CFlightPlanComponent::fillWithFlightPlanData(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_CruiseTrueAirspeed->setText(flightPlan.getCruiseTrueAirspeed().valueRoundedWithUnit(BlackMisc::PhysicalQuantities::CSpeedUnit::kts(), 0));
CAltitude cruiseAlt = flightPlan.getCruiseAltitude();
if (cruiseAlt.isFlightLevel())
{
this->ui->le_CrusingAltitude->setText(cruiseAlt.toQString());
}
else
{
this->ui->le_CrusingAltitude->setText(cruiseAlt.valueRoundedWithUnit(BlackMisc::PhysicalQuantities::CLengthUnit::ft(), 0));
}
}
CFlightPlan CFlightPlanComponent::getFlightPlan() const
{
return this->m_flightPlan;
}
void CFlightPlanComponent::runtimeHasBeenSet()
{
// context dependent calls
this->ps_resetFlightPlan();
this->ps_buildRemarksString();
}
BlackMisc::CStatusMessageList CFlightPlanComponent::validateAndInitializeFlightPlan(BlackMisc::Aviation::CFlightPlan &flightPlan)
{
BlackMisc::CStatusMessageList messages;
QString v;
CFlightPlan::FlightRules rule = CFlightPlan::IFR;
if (this->ui->rb_TypeIfr->isChecked())
{
rule = CFlightPlan::IFR;
}
else if (this->ui->rb_TypeVfr->isChecked())
{
rule = CFlightPlan::VFR;
}
flightPlan.setFlightRule(rule);
v = ui->le_Callsign->text().trimmed();
if (v.isEmpty())
{
messages.push_back(CLogMessage().validationWarning("Missing %1") << this->ui->lbl_Callsign->text());
}
v = ui->pte_Route->toPlainText().trimmed();
if (v.isEmpty())
{
messages.push_back(CLogMessage().validationWarning("Missing flight plan route"));
}
else if (v.length() > CFlightPlan::MaxRouteLength)
{
messages.push_back(CLogMessage().validationWarning("Flight plan route length exceeded (%1 chars max.)") << CFlightPlan::MaxRouteLength);
}
else
{
flightPlan.setRoute(v);
}
v = ui->pte_Remarks->toPlainText().trimmed();
if (v.isEmpty())
{
messages.push_back(CLogMessage().validationWarning("No remarks, voice capabilities are mandatory"));
}
else if (v.length() > CFlightPlan::MaxRemarksLength)
{
messages.push_back(CLogMessage().validationWarning("Flight plan remarks length exceeded (%1 chars max.)") << CFlightPlan::MaxRemarksLength);
}
else
{
flightPlan.setRemarks(v);
}
v = ui->le_EstimatedTimeEnroute->text();
if (v.isEmpty() || v == defaultTime())
{
messages.push_back(CLogMessage().validationWarning("Missing %1") << this->ui->lbl_EstimatedTimeEnroute->text());
}
else
{
flightPlan.setEnrouteTime(v);
}
v = ui->le_FuelOnBoard->text();
if (v.isEmpty() || v == defaultTime())
{
messages.push_back(CLogMessage().validationWarning("Missing %1") << this->ui->lbl_FuelOnBorad->text());
}
else
{
flightPlan.setFuelTime(v);
}
v = ui->le_TakeOffTimePlanned->text();
if (v.isEmpty() || v == defaultTime())
{
messages.push_back(CLogMessage().validationWarning("Missing %1") << this->ui->lbl_TakeOffTimePlanned->text());
}
else
{
flightPlan.setTakeoffTimePlanned(v);
}
static const QRegExp withUnit("\\D+");
v = ui->le_CrusingAltitude->text().trimmed();
if (!v.isEmpty() && withUnit.indexIn(v) < 0)
{
v += "ft";
this->ui->le_CrusingAltitude->setText(v);
}
CAltitude cruisingAltitude(v, CPqString::SeparatorsLocale);
if (v.isEmpty() || cruisingAltitude.isNull())
{
messages.push_back(CLogMessage().validationWarning("Wrong %1") << this->ui->lbl_CrusingAltitude->text());
}
else
{
flightPlan.setCruiseAltitude(cruisingAltitude);
}
v = this->ui->le_AlternateAirport->text();
if (v.isEmpty() || v.endsWith(defaultIcao(), Qt::CaseInsensitive))
{
messages.push_back(CLogMessage().validationWarning("Missing %1") << this->ui->lbl_AlternateAirport->text());
flightPlan.setAlternateAirportIcao(defaultIcao());
}
else
{
flightPlan.setAlternateAirportIcao(v);
}
v = this->ui->le_DestinationAirport->text();
if (v.isEmpty() || v.endsWith(defaultIcao(), Qt::CaseInsensitive))
{
messages.push_back(CLogMessage().validationWarning("Missing %1") << this->ui->lbl_DestinationAirport->text());
flightPlan.setDestinationAirportIcao(defaultIcao());
}
else
{
flightPlan.setDestinationAirportIcao(v);
}
v = this->ui->le_CruiseTrueAirspeed->text();
BlackMisc::PhysicalQuantities::CSpeed cruiseTAS;
cruiseTAS.parseFromString(v, CPqString::SeparatorsLocale);
if (cruiseTAS.isNull())
{
messages.push_back(CLogMessage().validationWarning("Wrong TAS, %1") << this->ui->lbl_CruiseTrueAirspeed->text());
flightPlan.setDestinationAirportIcao(defaultIcao());
}
else
{
flightPlan.setCruiseTrueAirspeed(cruiseTAS);
}
v = this->ui->le_OriginAirport->text();
if (v.isEmpty() || v.endsWith(defaultIcao(), Qt::CaseInsensitive))
{
messages.push_back(CLogMessage().validationWarning("Missing %1") << this->ui->lbl_OriginAirport->text());
flightPlan.setOriginAirportIcao(defaultIcao());
}
else
{
flightPlan.setOriginAirportIcao(v);
}
return messages;
}
void CFlightPlanComponent::ps_sendFlightPlan()
{
CFlightPlan flightPlan;
CStatusMessageList messages = this->validateAndInitializeFlightPlan(flightPlan);
if (messages.isEmpty())
{
// no error, send if possible
if (this->getIContextNetwork()->isConnected())
{
flightPlan.setWhenLastSentOrLoaded(QDateTime::currentDateTimeUtc());
this->getIContextNetwork()->sendFlightPlan(flightPlan);
this->ui->le_LastSent->setText(flightPlan.whenLastSentOrLoaded().toString());
CLogMessage(this).info("Sent flight plan");
}
else
{
flightPlan.setWhenLastSentOrLoaded(QDateTime()); // empty
this->ui->le_LastSent->clear();
CLogMessage(this).error("No errors, but not connected, cannot send flight plan");
}
this->m_flightPlan = flightPlan; // last valid FP
}
}
void CFlightPlanComponent::ps_validateFlightPlan()
{
CFlightPlan flightPlan;
CStatusMessageList messages = this->validateAndInitializeFlightPlan(flightPlan);
messages.addCategories(this);
messages.addCategory(CLogCategory::validation());
CLogMessage::preformatted(messages);
}
void CFlightPlanComponent::ps_resetFlightPlan()
{
Q_ASSERT(this->getIContextNetwork());
Q_ASSERT(this->getIContextOwnAircraft());
if (this->getIContextOwnAircraft()) { this->prefillWithAircraftData(this->getIContextOwnAircraft()->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::ps_setSelcalInOwnAircraft()
{
if (!this->getIContextOwnAircraft()) return;
if (!this->ui->frp_SelcalCode->hasValidCode()) return;
this->getIContextOwnAircraft()->updateSelcal(this->ui->frp_SelcalCode->getSelcal(), flightPlanIdentifier());
}
void CFlightPlanComponent::ps_loadFlightPlanFromNetwork()
{
if (!this->getIContextNetwork())
{
CLogMessage(this).info("Cannot load flight plan, network not available");
return;
}
if (!this->getIContextNetwork()->isConnected())
{
CLogMessage(this).warning("Cannot load flight plan, network not connected");
return;
}
CSimulatedAircraft ownAircraft = this->getIContextOwnAircraft()->getOwnAircraft();
CFlightPlan loadedPlan = this->getIContextNetwork()->loadFlightPlanFromNetwork(ownAircraft.getCallsign());
if (loadedPlan.wasSentOrLoaded())
{
this->fillWithFlightPlanData(loadedPlan);
CLogMessage(this).info("Updated with loaded flight plan");
}
else
{
CLogMessage(this).warning("No flight plan data");
}
}
void CFlightPlanComponent::ps_buildRemarksString()
{
QString rem;
QString v = this->ui->cb_VoiceCapabilities->currentText().toUpper();
if (v.contains("TEXT")) { rem.append("/T/ "); }
else if (v.contains("RECEIVE")) { rem.append("/R/ "); }
else if (v.contains("VOICE")) { rem.append("/V/ "); }
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 "); }
else if (v.startsWith("E")) { rem.append("PER/E "); }
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::ps_copyRemarks()
{
this->ui->pte_Remarks->setPlainText(this->ui->pte_RemarksGenerated->toPlainText());
CLogMessage(this).info("Copied remarks");
}
void CFlightPlanComponent::ps_currentTabGenerator()
{
this->setCurrentWidget(this->ui->tb_RemarksGenerator);
}
CIdentifier CFlightPlanComponent::flightPlanIdentifier()
{
if (m_identifier.getName().isEmpty()) { m_identifier = CIdentifier(QStringLiteral("FLIGHTPLANCOMPONENT")); }
return m_identifier;
}
} // namespace
} // namespace