mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-02 06:35:52 +08:00
634 lines
26 KiB
C++
634 lines
26 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 "blackcore/context/contextnetwork.h"
|
|
#include "blackcore/context/contextownaircraft.h"
|
|
#include "blackcore/webdataservices.h"
|
|
#include "blackgui/uppercasevalidator.h"
|
|
#include "blackgui/components/flightplancomponent.h"
|
|
#include "blackgui/components/selcalcodeselector.h"
|
|
#include "blackgui/guiapplication.h"
|
|
#include "blackmisc/aviation/aircrafticaocode.h"
|
|
#include "blackmisc/aviation/airportlist.h"
|
|
#include "blackmisc/aviation/altitude.h"
|
|
#include "blackmisc/aviation/callsign.h"
|
|
#include "blackmisc/logcategory.h"
|
|
#include "blackmisc/logmessage.h"
|
|
#include "blackconfig/buildconfig.h"
|
|
#include "blackmisc/network/user.h"
|
|
#include "blackmisc/pq/pqstring.h"
|
|
#include "blackmisc/pq/speed.h"
|
|
#include "blackmisc/pq/units.h"
|
|
#include "blackmisc/simulation/simulatedaircraft.h"
|
|
#include "blackmisc/directoryutils.h"
|
|
#include "blackmisc/statusmessage.h"
|
|
#include "ui_flightplancomponent.h"
|
|
|
|
#include <QCheckBox>
|
|
#include <QComboBox>
|
|
#include <QDateTime>
|
|
#include <QLabel>
|
|
#include <QLineEdit>
|
|
#include <QPlainTextEdit>
|
|
#include <QPushButton>
|
|
#include <QRadioButton>
|
|
#include <QRegularExpression>
|
|
#include <QTabBar>
|
|
#include <QCompleter>
|
|
#include <Qt>
|
|
|
|
using namespace BlackMisc;
|
|
using namespace BlackMisc::Aviation;
|
|
using namespace BlackMisc::Simulation;
|
|
using namespace BlackMisc::PhysicalQuantities;
|
|
using namespace BlackGui;
|
|
using namespace BlackCore;
|
|
using namespace BlackConfig;
|
|
|
|
namespace BlackGui
|
|
{
|
|
namespace Components
|
|
{
|
|
CFlightPlanComponent::CFlightPlanComponent(QWidget *parent) :
|
|
QTabWidget(parent),
|
|
ui(new Ui::CFlightPlanComponent)
|
|
{
|
|
Q_ASSERT_X(sGui, Q_FUNC_INFO, "missing sGui");
|
|
Q_ASSERT_X(sGui->hasWebDataServices(), Q_FUNC_INFO, "missing web services");
|
|
|
|
// UI
|
|
ui->setupUi(this);
|
|
|
|
// fix style
|
|
this->tabBar()->setExpanding(false);
|
|
this->tabBar()->setUsesScrollButtons(true);
|
|
|
|
// validators
|
|
CUpperCaseValidator *ucv = new CUpperCaseValidator(this);
|
|
ui->le_Callsign->setValidator(ucv);
|
|
ui->le_AircraftType->setValidator(ucv);
|
|
ui->le_DestinationAirport->setValidator(ucv);
|
|
ui->le_AlternateAirport->setValidator(ucv);
|
|
ui->le_OriginAirport->setValidator(ucv);
|
|
|
|
// connect
|
|
connect(ui->pb_Send, &QPushButton::pressed, this, &CFlightPlanComponent::ps_sendFlightPlan);
|
|
connect(ui->pb_Load, &QPushButton::pressed, this, &CFlightPlanComponent::ps_loadFlightPlanFromNetwork);
|
|
connect(ui->pb_Reset, &QPushButton::pressed, this, &CFlightPlanComponent::ps_resetFlightPlan);
|
|
connect(ui->pb_ValidateFlightPlan, &QPushButton::pressed, this, &CFlightPlanComponent::ps_validateFlightPlan);
|
|
|
|
connect(ui->cb_VoiceCapabilities, &QComboBox::currentTextChanged, this, &CFlightPlanComponent::ps_currentTextChangedToBuildRemarks);
|
|
connect(ui->cb_NavigationEquipment, &QComboBox::currentTextChanged, this, &CFlightPlanComponent::ps_currentTextChangedToBuildRemarks);
|
|
connect(ui->cb_PerformanceCategory, &QComboBox::currentTextChanged, this, &CFlightPlanComponent::ps_currentTextChangedToBuildRemarks);
|
|
connect(ui->cb_PilotRating, &QComboBox::currentTextChanged, this, &CFlightPlanComponent::ps_currentTextChangedToBuildRemarks);
|
|
connect(ui->cb_RequiredNavigationPerformance, &QComboBox::currentTextChanged, this, &CFlightPlanComponent::ps_currentTextChangedToBuildRemarks);
|
|
|
|
connect(ui->pb_LoadDisk, &QPushButton::clicked, this, &CFlightPlanComponent::ps_loadFromDisk);
|
|
connect(ui->pb_SaveDisk, &QPushButton::clicked, this, &CFlightPlanComponent::ps_saveToDisk);
|
|
|
|
bool c = connect(ui->le_AircraftRegistration, SIGNAL(textChanged(QString)), this, SLOT(ps_buildRemarksString()));
|
|
Q_ASSERT_X(c, Q_FUNC_INFO, "failed connect");
|
|
c = connect(ui->cb_NoSidsStarts, SIGNAL(toggled(bool)), this, SLOT(ps_buildRemarksString()));
|
|
Q_ASSERT_X(c, Q_FUNC_INFO, "failed connect");
|
|
c = connect(ui->le_AirlineOperator, SIGNAL(textChanged(QString)), this, SLOT(ps_buildRemarksString()));
|
|
Q_ASSERT_X(c, Q_FUNC_INFO, "failed connect");
|
|
Q_UNUSED(c);
|
|
|
|
connect(ui->pte_AdditionalRemarks, &QPlainTextEdit::textChanged, this, &CFlightPlanComponent::ps_buildRemarksString);
|
|
connect(ui->frp_SelcalCode, &CSelcalCodeSelector::valueChanged, this, &CFlightPlanComponent::ps_buildRemarksString);
|
|
connect(ui->frp_SelcalCode, &CSelcalCodeSelector::valueChanged, this, &CFlightPlanComponent::ps_setSelcalInOwnAircraft);
|
|
connect(ui->pb_CopyOver, &QPushButton::pressed, this, &CFlightPlanComponent::ps_copyRemarks);
|
|
connect(ui->pb_RemarksGenerator, &QPushButton::clicked, this, &CFlightPlanComponent::ps_currentTabGenerator);
|
|
|
|
// web services
|
|
connect(sGui->getWebDataServices(), &CWebDataServices::allSwiftDbDataRead, this, &CFlightPlanComponent::ps_swiftWebDataRead);
|
|
|
|
// init GUI
|
|
this->ps_resetFlightPlan();
|
|
this->ps_buildRemarksString();
|
|
}
|
|
|
|
CFlightPlanComponent::~CFlightPlanComponent()
|
|
{ }
|
|
|
|
void CFlightPlanComponent::loginDataSet()
|
|
{
|
|
if (m_flightPlan.wasSentOrLoaded()) { return; } // when loaded or sent do not override
|
|
if (!sGui->getIContextOwnAircraft()) { return; }
|
|
|
|
const CSimulatedAircraft ownAircraft(sGui->getIContextOwnAircraft()->getOwnAircraft());
|
|
this->prefillWithAircraftData(ownAircraft);
|
|
this->prefillWithUserData(ownAircraft.getPilot());
|
|
}
|
|
|
|
void CFlightPlanComponent::prefillWithAircraftData(const BlackMisc::Simulation::CSimulatedAircraft &ownAircraft)
|
|
{
|
|
if (m_flightPlan.wasSentOrLoaded()) { return; }
|
|
|
|
// only override with valid values
|
|
if (CCallsign::isValidAircraftCallsign(ownAircraft.getCallsignAsString()))
|
|
{
|
|
ui->le_Callsign->setText(ownAircraft.getCallsign().asString());
|
|
}
|
|
if (CAircraftIcaoCode::isValidDesignator(ownAircraft.getAircraftIcaoCodeDesignator()))
|
|
{
|
|
ui->le_AircraftType->setText(ownAircraft.getAircraftIcaoCodeDesignator());
|
|
}
|
|
if (ownAircraft.hasValidRealName())
|
|
{
|
|
ui->le_PilotsName->setText(ownAircraft.getPilot().getRealName());
|
|
}
|
|
}
|
|
|
|
void CFlightPlanComponent::prefillWithUserData(const Network::CUser &user)
|
|
{
|
|
if (m_flightPlan.wasSentOrLoaded()) { return; }
|
|
if (user.hasValidRealName())
|
|
{
|
|
ui->le_PilotsName->setText(user.getRealName());
|
|
}
|
|
if (user.hasHomeBase())
|
|
{
|
|
ui->le_PilotsHomeBase->setText(user.getHomeBase().getIcaoCode());
|
|
}
|
|
if (user.hasValidCallsign())
|
|
{
|
|
ui->le_Callsign->setText(user.getCallsign().asString());
|
|
}
|
|
}
|
|
|
|
void CFlightPlanComponent::fillWithFlightPlanData(const BlackMisc::Aviation::CFlightPlan &flightPlan)
|
|
{
|
|
ui->le_AlternateAirport->setText(flightPlan.getAlternateAirportIcao().asString());
|
|
ui->le_DestinationAirport->setText(flightPlan.getDestinationAirportIcao().asString());
|
|
ui->le_OriginAirport->setText(flightPlan.getOriginAirportIcao().asString());
|
|
ui->pte_Route->setPlainText(flightPlan.getRoute());
|
|
ui->pte_Remarks->setPlainText(flightPlan.getRemarks());
|
|
ui->le_TakeOffTimePlanned->setText(flightPlan.getTakeoffTimePlannedHourMin());
|
|
ui->le_FuelOnBoard->setText(flightPlan.getFuelTimeHourMin());
|
|
ui->le_EstimatedTimeEnroute->setText(flightPlan.getEnrouteTimeHourMin());
|
|
ui->le_CruiseTrueAirspeed->setText(flightPlan.getCruiseTrueAirspeed().valueRoundedWithUnit(CSpeedUnit::kts(), 0));
|
|
|
|
const CAltitude cruiseAlt = flightPlan.getCruiseAltitude();
|
|
if (cruiseAlt.isFlightLevel())
|
|
{
|
|
ui->le_CrusingAltitude->setText(cruiseAlt.toQString());
|
|
}
|
|
else
|
|
{
|
|
ui->le_CrusingAltitude->setText(cruiseAlt.valueRoundedWithUnit(CLengthUnit::ft(), 0));
|
|
}
|
|
|
|
switch (flightPlan.getFlightRulesAsVFRorIFR())
|
|
{
|
|
case CFlightPlan::VFR:
|
|
ui->rb_TypeVfr->setChecked(true);
|
|
break;
|
|
default:
|
|
ui->rb_TypeIfr->setChecked(true);
|
|
break;
|
|
}
|
|
}
|
|
|
|
CFlightPlan CFlightPlanComponent::getFlightPlan() const
|
|
{
|
|
return m_flightPlan;
|
|
}
|
|
|
|
BlackMisc::CStatusMessageList CFlightPlanComponent::validateAndInitializeFlightPlan(CFlightPlan &flightPlan)
|
|
{
|
|
BlackMisc::CStatusMessageList messages;
|
|
QString v;
|
|
|
|
CFlightPlan::FlightRules rule = CFlightPlan::IFR;
|
|
if (ui->rb_TypeIfr->isChecked())
|
|
{
|
|
rule = CFlightPlan::IFR;
|
|
}
|
|
else if (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") << 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") << 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") << 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") << ui->lbl_TakeOffTimePlanned->text());
|
|
}
|
|
else
|
|
{
|
|
flightPlan.setTakeoffTimePlanned(v);
|
|
}
|
|
|
|
thread_local const QRegularExpression withUnit("\\D+");
|
|
v = ui->le_CrusingAltitude->text().trimmed();
|
|
if (!v.isEmpty() && !withUnit.match(v).hasMatch())
|
|
{
|
|
v += "ft";
|
|
ui->le_CrusingAltitude->setText(v);
|
|
}
|
|
|
|
CAltitude cruisingAltitude(v, CPqString::SeparatorsLocale);
|
|
if (v.isEmpty() || cruisingAltitude.isNull())
|
|
{
|
|
messages.push_back(CLogMessage().validationWarning("Wrong %1") << ui->lbl_CrusingAltitude->text());
|
|
}
|
|
else
|
|
{
|
|
flightPlan.setCruiseAltitude(cruisingAltitude);
|
|
}
|
|
|
|
v = ui->le_DestinationAirport->text();
|
|
if (v.isEmpty() || v.endsWith(defaultIcao(), Qt::CaseInsensitive))
|
|
{
|
|
messages.push_back(CLogMessage().validationWarning("Missing %1") << ui->lbl_DestinationAirport->text());
|
|
flightPlan.setDestinationAirportIcao(QString(""));
|
|
}
|
|
else
|
|
{
|
|
flightPlan.setDestinationAirportIcao(v);
|
|
}
|
|
|
|
v = ui->le_CruiseTrueAirspeed->text();
|
|
CSpeed cruiseTAS;
|
|
cruiseTAS.parseFromString(v, CPqString::SeparatorsLocale);
|
|
if (cruiseTAS.isNull())
|
|
{
|
|
messages.push_back(CLogMessage().validationWarning("Wrong TAS, %1") << ui->lbl_CruiseTrueAirspeed->text());
|
|
flightPlan.setDestinationAirportIcao(defaultIcao());
|
|
}
|
|
else
|
|
{
|
|
flightPlan.setCruiseTrueAirspeed(cruiseTAS);
|
|
}
|
|
|
|
v = ui->le_OriginAirport->text();
|
|
if (v.isEmpty() || v.endsWith(defaultIcao(), Qt::CaseInsensitive))
|
|
{
|
|
messages.push_back(CLogMessage().validationWarning("Missing %1") << ui->lbl_OriginAirport->text());
|
|
flightPlan.setOriginAirportIcao(defaultIcao());
|
|
}
|
|
else
|
|
{
|
|
flightPlan.setOriginAirportIcao(v);
|
|
}
|
|
|
|
// Optional fields
|
|
v = ui->le_AlternateAirport->text();
|
|
if (v.isEmpty() || v.endsWith(defaultIcao(), Qt::CaseInsensitive))
|
|
{
|
|
if (!messages.hasWarningOrErrorMessages())
|
|
{
|
|
messages.push_back(CLogMessage().validationInfo("Missing %1") << ui->lbl_AlternateAirport->text());
|
|
}
|
|
flightPlan.setAlternateAirportIcao(QString(""));
|
|
}
|
|
else
|
|
{
|
|
flightPlan.setAlternateAirportIcao(v);
|
|
}
|
|
|
|
// OK
|
|
if (!messages.hasWarningOrErrorMessages())
|
|
{
|
|
messages.push_back(CLogMessage().validationInfo("Flight plan validation passed"));
|
|
}
|
|
return messages;
|
|
}
|
|
|
|
void CFlightPlanComponent::ps_sendFlightPlan()
|
|
{
|
|
CFlightPlan flightPlan;
|
|
CStatusMessageList messages = this->validateAndInitializeFlightPlan(flightPlan);
|
|
if (messages.isEmpty())
|
|
{
|
|
// no error, send if possible
|
|
if (sGui->getIContextNetwork()->isConnected())
|
|
{
|
|
flightPlan.setWhenLastSentOrLoaded(QDateTime::currentDateTimeUtc());
|
|
sGui->getIContextNetwork()->sendFlightPlan(flightPlan);
|
|
ui->le_LastSent->setText(flightPlan.whenLastSentOrLoaded().toString());
|
|
CLogMessage(this).info("Sent flight plan");
|
|
}
|
|
else
|
|
{
|
|
flightPlan.setWhenLastSentOrLoaded(QDateTime()); // empty
|
|
ui->le_LastSent->clear();
|
|
CLogMessage(this).error("No errors, but not connected, cannot send flight plan");
|
|
}
|
|
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(sGui->getIContextNetwork());
|
|
Q_ASSERT(sGui->getIContextOwnAircraft());
|
|
if (sGui->getIContextOwnAircraft()) { this->prefillWithAircraftData(sGui->getIContextOwnAircraft()->getOwnAircraft()); }
|
|
ui->le_AircraftRegistration->clear();
|
|
ui->le_AirlineOperator->clear();
|
|
ui->le_CrusingAltitude->setText("FL70");
|
|
ui->le_CruiseTrueAirspeed->setText("100 kts");
|
|
ui->pte_Remarks->clear();
|
|
ui->pte_Route->clear();
|
|
ui->le_AlternateAirport->clear();
|
|
ui->le_DestinationAirport->clear();
|
|
ui->le_OriginAirport->clear();
|
|
ui->le_FuelOnBoard->setText(defaultTime());
|
|
ui->le_EstimatedTimeEnroute->setText(defaultTime());
|
|
ui->le_TakeOffTimePlanned->setText(QDateTime::currentDateTimeUtc().addSecs(30 * 60).toString("hh:mm"));
|
|
}
|
|
|
|
void CFlightPlanComponent::ps_loadFromDisk()
|
|
{
|
|
CStatusMessage m;
|
|
const QString fileName = QFileDialog::getOpenFileName(nullptr,
|
|
tr("Load flight plan"), getDefaultFilename(true),
|
|
tr("swift (*.json *.txt)"));
|
|
do
|
|
{
|
|
if (fileName.isEmpty())
|
|
{
|
|
m = CStatusMessage(this, CStatusMessage::SeverityDebug, "Load canceled", true);
|
|
break;
|
|
}
|
|
|
|
const QString json(CFileUtils::readFileToString(fileName));
|
|
if (!Json::looksLikeSwiftJson(json))
|
|
{
|
|
m = CStatusMessage(this, CStatusMessage::SeverityWarning, "Reading '%1' yields no data", true) << fileName;
|
|
break;
|
|
}
|
|
|
|
try
|
|
{
|
|
CVariant variant;
|
|
variant.convertFromJson(Json::jsonObjectFromString(json));
|
|
if (variant.canConvert<CFlightPlan>())
|
|
{
|
|
const CFlightPlan fp = variant.value<CFlightPlan>();
|
|
this->fillWithFlightPlanData(fp);
|
|
}
|
|
else
|
|
{
|
|
m = CStatusMessage(this, CStatusMessage::SeverityWarning, "Wrong format for flight plan in '%1'") << fileName;
|
|
}
|
|
}
|
|
catch (const CJsonException &ex)
|
|
{
|
|
m = ex.toStatusMessage(this, "Parse error in " + fileName);
|
|
break;
|
|
}
|
|
}
|
|
while (false);
|
|
if (m.isFailure()) { CLogMessage::preformatted(m); }
|
|
}
|
|
|
|
void CFlightPlanComponent::ps_saveToDisk()
|
|
{
|
|
CStatusMessage m;
|
|
const QString fileName = QFileDialog::getSaveFileName(nullptr,
|
|
tr("Save flight plan"), getDefaultFilename(false),
|
|
tr("swift (*.json *.txt)"));
|
|
do
|
|
{
|
|
if (fileName.isEmpty())
|
|
{
|
|
m = CStatusMessage(this, CStatusMessage::SeverityDebug, "Save canceled", true);
|
|
break;
|
|
}
|
|
CFlightPlan fp;
|
|
this->validateAndInitializeFlightPlan(fp); // get data
|
|
const CVariant variantFp = CVariant::fromValue(fp);
|
|
const QString json(variantFp.toJsonString());
|
|
const bool ok = CFileUtils::writeStringToFile(json, fileName);
|
|
if (ok)
|
|
{
|
|
m = CStatusMessage(this, CStatusMessage::SeverityInfo, "Written " + fileName, true);
|
|
}
|
|
else
|
|
{
|
|
m = CStatusMessage(this, CStatusMessage::SeverityError, "Writing " + fileName + " failed", true);
|
|
}
|
|
}
|
|
while (false);
|
|
if (m.isFailure()) { CLogMessage::preformatted(m); }
|
|
}
|
|
|
|
void CFlightPlanComponent::ps_setSelcalInOwnAircraft()
|
|
{
|
|
if (!sGui->getIContextOwnAircraft()) return;
|
|
if (!ui->frp_SelcalCode->hasValidCode()) return;
|
|
sGui->getIContextOwnAircraft()->updateSelcal(ui->frp_SelcalCode->getSelcal(), flightPlanIdentifier());
|
|
}
|
|
|
|
void CFlightPlanComponent::ps_loadFlightPlanFromNetwork()
|
|
{
|
|
if (!sGui->getIContextNetwork())
|
|
{
|
|
CLogMessage(this).info("Cannot load flight plan, network not available");
|
|
return;
|
|
}
|
|
if (!sGui->getIContextNetwork()->isConnected())
|
|
{
|
|
CLogMessage(this).warning("Cannot load flight plan, network not connected");
|
|
return;
|
|
}
|
|
|
|
const CSimulatedAircraft ownAircraft = sGui->getIContextOwnAircraft()->getOwnAircraft();
|
|
const CFlightPlan loadedPlan = sGui->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 = 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 = ui->le_AirlineOperator->text().trimmed();
|
|
if (!v.isEmpty()) rem.append("OPR/").append(v).append(" ");
|
|
|
|
v = ui->le_AircraftRegistration->text().trimmed();
|
|
if (!v.isEmpty()) rem.append("REG/").append(v).append(" ");
|
|
|
|
v = 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 = ui->cb_RequiredNavigationPerformance->currentText().toUpper();
|
|
if (v.contains("10")) { rem.append("RNP10 "); }
|
|
else if (v.contains("4")) { rem.append("RNP4 "); }
|
|
|
|
v = 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 = 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 (ui->frp_SelcalCode->hasValidCode())
|
|
{
|
|
rem.append("SEL/").append(ui->frp_SelcalCode->getSelcalCode());
|
|
rem.append(" ");
|
|
}
|
|
|
|
if (ui->cb_NoSidsStarts->isChecked()) { rem.append("NO SID/STAR "); }
|
|
|
|
v = ui->pte_AdditionalRemarks->toPlainText().trimmed();
|
|
if (!v.isEmpty()) { rem.append(v); }
|
|
|
|
rem = rem.simplified().trimmed();
|
|
ui->pte_RemarksGenerated->setPlainText(rem);
|
|
}
|
|
|
|
void CFlightPlanComponent::ps_copyRemarks()
|
|
{
|
|
ui->pte_Remarks->setPlainText(ui->pte_RemarksGenerated->toPlainText());
|
|
CLogMessage(this).info("Copied remarks");
|
|
}
|
|
|
|
void CFlightPlanComponent::ps_currentTabGenerator()
|
|
{
|
|
this->setCurrentWidget(ui->tb_RemarksGenerator);
|
|
}
|
|
|
|
void CFlightPlanComponent::ps_swiftWebDataRead()
|
|
{
|
|
this->initCompleters();
|
|
}
|
|
|
|
CIdentifier CFlightPlanComponent::flightPlanIdentifier()
|
|
{
|
|
if (m_identifier.getName().isEmpty()) { m_identifier = CIdentifier(QStringLiteral("FLIGHTPLANCOMPONENT")); }
|
|
return m_identifier;
|
|
}
|
|
|
|
void CFlightPlanComponent::initCompleters()
|
|
{
|
|
if (!sGui || !sGui->getWebDataServices()) { return; }
|
|
const QStringList aircraft(sGui->getWebDataServices()->getAircraftIcaoCodes().allIcaoCodes().toList());
|
|
ui->le_AircraftType->setCompleter(new QCompleter(aircraft, this));
|
|
|
|
const QStringList airports = sGui->getWebDataServices()->getAirports().allIcaoCodes(true);
|
|
QCompleter *airportCompleter = new QCompleter(airports, this);
|
|
ui->le_AlternateAirport->setCompleter(airportCompleter);
|
|
ui->le_DestinationAirport->setCompleter(airportCompleter);
|
|
ui->le_OriginAirport->setCompleter(airportCompleter);
|
|
}
|
|
|
|
QString CFlightPlanComponent::getDefaultFilename(bool load)
|
|
{
|
|
// some logic to find a useful default name
|
|
QString dir = CDirectoryUtils::documentationDirectory();
|
|
|
|
if (load)
|
|
{
|
|
return CFileUtils::appendFilePaths(dir, CFileUtils::jsonWildcardAppendix());
|
|
}
|
|
|
|
// Save file path
|
|
QString name("Flight plan");
|
|
if (!ui->le_DestinationAirport->text().isEmpty() && !ui->le_OriginAirport->text().isEmpty())
|
|
{
|
|
name.append(" ").append(ui->le_OriginAirport->text()).append("-").append(ui->le_DestinationAirport->text());
|
|
}
|
|
|
|
if (!name.endsWith(CFileUtils::jsonAppendix(), Qt::CaseInsensitive))
|
|
{
|
|
name += CFileUtils::jsonAppendix();
|
|
}
|
|
return CFileUtils::appendFilePaths(dir, name);
|
|
}
|
|
} // namespace
|
|
} // namespace
|