10 #include <QDesktopServices>
14 #include <QMessageBox>
15 #include <QPlainTextEdit>
17 #include <QPushButton>
18 #include <QRadioButton>
19 #include <QStringBuilder>
21 #include <QToolButton>
22 #include <QWidgetAction>
25 #include "ui_flightplancomponent.h"
56 using namespace swift::misc::aviation;
57 using namespace swift::misc::network;
58 using namespace swift::misc::simulation;
59 using namespace swift::misc::physical_quantities;
62 using namespace swift::config;
66 CFlightPlanComponent::CFlightPlanComponent(QWidget *parent)
69 Q_ASSERT_X(
sGui, Q_FUNC_INFO,
"missing sGui");
74 this->setCurrentIndex(0);
77 for (
const WakeTurbulenceEntry &item : std::as_const(m_wakeTurbulenceCategories))
79 ui->cb_Wtc->addItem(item.m_name);
83 this->tabBar()->setExpanding(
false);
84 this->tabBar()->setUsesScrollButtons(
true);
91 setupNavComContextMenu();
92 setupSsrContextMenu();
95 ui->cb_FlightRule->clear();
96 ui->cb_FlightRule->addItems(CFlightPlan::flightRules());
101 ui->le_DestinationAirport->setValidator(
new CUpperCaseValidator(ui->le_DestinationAirport));
105 ui->le_AircraftRegistration->setValidator(
new CUpperCaseValidator(ui->le_AircraftRegistration));
107 ui->le_NavComEquipment->setReadOnly(
true);
108 ui->le_SsrEquipment->setReadOnly(
true);
111 ui->pte_Route->installEventFilter(ef);
113 ui->pte_Remarks->installEventFilter(ef);
115 ui->pte_AdditionalRemarks->installEventFilter(ef);
118 connect(ui->pb_Send, &QPushButton::pressed,
this, &CFlightPlanComponent::sendFlightPlan, Qt::QueuedConnection);
119 connect(ui->pb_Download, &QPushButton::pressed,
this, &CFlightPlanComponent::loadFlightPlanFromNetwork,
120 Qt::QueuedConnection);
121 connect(ui->pb_Reset, &QPushButton::pressed,
this, &CFlightPlanComponent::resetFlightPlan,
122 Qt::QueuedConnection);
123 connect(ui->tb_SyncWithSimulator, &QPushButton::released,
this, &CFlightPlanComponent::syncWithSimulator,
124 Qt::QueuedConnection);
125 connect(ui->pb_SimBrief, &QPushButton::pressed,
this, &CFlightPlanComponent::loadFromSimBrief,
126 Qt::QueuedConnection);
128 connect(ui->pb_SaveTemplate, &QPushButton::released,
this, &CFlightPlanComponent::saveTemplateToDisk,
129 Qt::QueuedConnection);
130 connect(ui->pb_LoadTemplate, &QPushButton::released,
this, &CFlightPlanComponent::loadTemplateFromDisk,
131 Qt::QueuedConnection);
132 connect(ui->pb_ClearTemplate, &QPushButton::released,
this, &CFlightPlanComponent::clearTemplate,
133 Qt::QueuedConnection);
135 connect(ui->cb_VoiceCapabilities, &QComboBox::currentTextChanged,
this,
136 &CFlightPlanComponent::currentTextChangedToBuildRemarks, Qt::QueuedConnection);
137 connect(ui->cb_VoiceCapabilities, &QComboBox::currentTextChanged,
this,
138 &CFlightPlanComponent::syncVoiceComboBoxes, Qt::QueuedConnection);
139 connect(ui->cb_VoiceCapabilitiesFirstPage, &QComboBox::currentTextChanged,
this,
140 &CFlightPlanComponent::syncVoiceComboBoxes, Qt::QueuedConnection);
141 connect(ui->cb_PerformanceCategory, &QComboBox::currentTextChanged,
this,
142 &CFlightPlanComponent::currentTextChangedToBuildRemarks, Qt::QueuedConnection);
143 connect(ui->cb_PilotRating, &QComboBox::currentTextChanged,
this,
144 &CFlightPlanComponent::currentTextChangedToBuildRemarks, Qt::QueuedConnection);
145 connect(ui->cb_RequiredNavigationPerformance, &QComboBox::currentTextChanged,
this,
146 &CFlightPlanComponent::currentTextChangedToBuildRemarks, Qt::QueuedConnection);
148 connect(ui->pb_LoadDisk, &QPushButton::clicked,
this, &CFlightPlanComponent::loadFromDisk,
149 Qt::QueuedConnection);
150 connect(ui->pb_SaveDisk, &QPushButton::clicked,
this, &CFlightPlanComponent::saveToDisk, Qt::QueuedConnection);
152 connect(ui->le_AircraftRegistration, &QLineEdit::textChanged,
this, &CFlightPlanComponent::buildRemarksString,
153 Qt::QueuedConnection);
154 connect(ui->le_AirlineOperator, &QLineEdit::textChanged,
this, &CFlightPlanComponent::buildRemarksString,
155 Qt::QueuedConnection);
156 connect(ui->cb_NoSidsStarts, &QCheckBox::released,
this, &CFlightPlanComponent::buildRemarksString,
157 Qt::QueuedConnection);
159 connect(ui->pte_AdditionalRemarks, &QPlainTextEdit::textChanged,
this,
160 &CFlightPlanComponent::buildRemarksString, Qt::QueuedConnection);
162 Qt::QueuedConnection);
164 &CFlightPlanComponent::setSelcalInOwnAircraft, Qt::QueuedConnection);
165 connect(ui->pb_CopyOver, &QPushButton::pressed,
this, &CFlightPlanComponent::copyRemarksConfirmed,
166 Qt::QueuedConnection);
167 connect(ui->pb_GetFromGenerator, &QPushButton::pressed,
this, &CFlightPlanComponent::copyRemarksConfirmed,
168 Qt::QueuedConnection);
169 connect(ui->pb_RemarksGenerator, &QPushButton::clicked,
this, &CFlightPlanComponent::currentTabGenerator,
170 Qt::QueuedConnection);
173 ui->tb_EditNavComEquipment, &QToolButton::clicked,
this,
174 [
this]() { m_navComEquipmentMenu->popup(QCursor::pos()); }, Qt::QueuedConnection);
176 ui->tb_NavComHelp, &QToolButton::clicked,
this,
177 []() { QDesktopServices::openUrl(sGui->getGlobalSetup().getComNavEquipmentHelpUrl()); },
178 Qt::QueuedConnection);
181 ui->tb_EditSsrEquipment, &QToolButton::clicked,
this,
182 [
this]() { m_ssrEquipmentMenu->popup(QCursor::pos()); }, Qt::QueuedConnection);
184 ui->tb_SsrHelp, &QToolButton::clicked,
this,
185 []() { QDesktopServices::openUrl(sGui->getGlobalSetup().getSsrEquipmentHelpUrl()); }, Qt::QueuedConnection);
187 connect(ui->tb_AltitudeDialog, &QToolButton::clicked,
this, &CFlightPlanComponent::altitudeDialog,
188 Qt::QueuedConnection);
190 connect(ui->le_AircraftType, &QLineEdit::editingFinished,
this, &CFlightPlanComponent::aircraftTypeChanged,
191 Qt::QueuedConnection);
193 connect(ui->pb_Remarks, &QPushButton::pressed,
this, &CFlightPlanComponent::remarksHistory,
194 Qt::QueuedConnection);
195 connect(ui->pb_AddRemarks, &QPushButton::pressed,
this, &CFlightPlanComponent::remarksHistory,
196 Qt::QueuedConnection);
200 &CFlightPlanComponent::swiftWebDataRead, Qt::QueuedConnection);
203 this->resetFlightPlan();
204 this->buildRemarksString();
207 const QPointer<CFlightPlanComponent> myself(
this);
211 this->loadTemplateFromDisk();
215 const CAircraftModel model = m_lastAircraftModel.get();
216 const CServer server = m_lastServer.get();
217 CSimulatedAircraft aircraft(model);
218 aircraft.setPilot(server.getUser());
219 this->prefillWithAircraftData(aircraft);
229 this->prefillWithOwnAircraftData();
232 void CFlightPlanComponent::prefillWithOwnAircraftData()
238 this->prefillWithAircraftData(ownAircraft);
241 void CFlightPlanComponent::prefillWithAircraftData(
const CSimulatedAircraft &aircraft,
bool force)
261 this->prefillWithUserData(aircraft.
getPilot());
264 void CFlightPlanComponent::prefillWithUserData(
const CUser &user)
279 ui->pte_Route->setPlainText(flightPlan.
getRoute());
280 ui->pte_Remarks->setPlainText(flightPlan.
getRemarks());
284 ui->le_CruiseTrueAirspeed->setText(
288 ui->lep_CrusingAltitude->setAltitude(cruiseAlt);
291 if (CFlightPlan::flightRules().contains(r, Qt::CaseInsensitive)) { ui->cb_FlightRule->setCurrentText(r); }
294 ui->cb_FlightRule->setCurrentText(CFlightPlan::flightRulesToString(CFlightPlan::IFR));
302 this->setRemarksUIValues(rem);
308 updateNavComEquipmentUi();
311 updateSsrEquipmentUi();
316 static const QStringList cats { CLogCategories::flightPlan(), CLogCategories::guiComponent() };
323 const bool vfr = this->isVfr();
330 v = ui->le_Callsign->text().trimmed().toUpper();
335 else if (!CCallsign::isValidAircraftCallsign(v))
342 v = ui->le_AircraftType->text().trimmed().toUpper();
347 else if (!CAircraftIcaoCode::isValidDesignator(v))
358 getSelectedWakeTurbulenceCategory());
362 v = ui->pte_Route->toPlainText().trimmed();
363 const int routeLength = v.length();
367 CStatusMessage(
this).validation(vfr ? CStatusMessage::SeverityInfo : CStatusMessage::SeverityWarning,
369 << ui->lbl_Route->text());
371 else if (routeLength > CFlightPlan::MaxRouteLength)
374 CStatusMessage(
this).validationError(u
"Flight plan route length exceeded (%1 chars max.)")
375 << CFlightPlan::MaxRouteLength);
380 v = ui->pte_Remarks->toPlainText().trimmed();
381 const int remarksLength = v.length();
385 << ui->pb_Remarks->text());
387 else if (remarksLength > CFlightPlan::MaxRemarksLength)
390 CStatusMessage(
this).validationError(u
"Flight plan remarks length exceeded (%1 chars max.)")
391 << CFlightPlan::MaxRemarksLength);
396 if ((remarksLength + routeLength) > CFlightPlan::MaxRouteAndRemarksLength)
399 u
"Flight plan route (%1) and remarks (%2) length exceeded (%3 chars max.)")
400 << routeLength << remarksLength << CFlightPlan::MaxRemarksLength);
404 v = ui->le_EstimatedTimeEnroute->text();
405 if (v.isEmpty() || v == defaultTime())
408 << ui->lbl_EstimatedTimeEnroute->text());
413 v = ui->le_FuelOnBoard->text();
414 if (v.isEmpty() || v == defaultTime())
421 v = ui->le_TakeOffTimePlanned->text();
422 if (v.isEmpty() || v == defaultTime())
425 << ui->lbl_TakeOffTimePlanned->text());
430 if (ui->lep_CrusingAltitude->isValid(&messages))
432 const CAltitude cruisingAltitude = ui->lep_CrusingAltitude->getAltitude();
437 v = ui->le_DestinationAirport->text();
438 if (v.isEmpty() || v.endsWith(defaultIcao(), Qt::CaseInsensitive))
441 << ui->lbl_DestinationAirport->text());
450 << ui->lbl_DestinationAirport->text());
455 v = ui->le_OriginAirport->text();
456 if (v.isEmpty() || v.endsWith(defaultIcao(), Qt::CaseInsensitive))
467 << ui->lbl_DestinationAirport->text());
472 v = ui->le_CruiseTrueAirspeed->text();
478 CStatusMessage(
this).validationError(u
"Wrong TAS, %1. Try adding a unit like '100kts' or '150km/h'")
479 << ui->lbl_CruiseTrueAirspeed->text());
485 v = ui->le_AlternateAirport->text();
486 if (v.isEmpty() || v.endsWith(defaultIcao(), Qt::CaseInsensitive))
491 << ui->lbl_AlternateAirport->text());
505 void CFlightPlanComponent::sendFlightPlan()
508 const CStatusMessageList messages = this->validateAndInitializeFlightPlan(flightPlan);
526 ui->le_LastSent->setText(lastSent);
530 this->updateRemarksHistories();
533 m_sentFlightPlan = flightPlan;
538 void CFlightPlanComponent::resetFlightPlan()
540 this->prefillWithOwnAircraftData();
541 ui->le_AircraftRegistration->clear();
542 ui->le_AirlineOperator->clear();
543 ui->lep_CrusingAltitude->setText(
"FL70");
544 ui->le_CruiseTrueAirspeed->setText(
"100 kts");
545 ui->pte_Remarks->clear();
546 ui->pte_Route->clear();
547 ui->le_AlternateAirport->clear();
548 ui->le_DestinationAirport->clear();
549 ui->le_OriginAirport->clear();
550 ui->le_FuelOnBoard->setText(defaultTime());
551 ui->le_EstimatedTimeEnroute->setText(defaultTime());
552 ui->le_TakeOffTimePlanned->setText(QDateTime::currentDateTimeUtc().addSecs(30 * 60).toString(
"hh:mm"));
553 this->syncVoiceComboBoxes(ui->cb_VoiceCapabilities->itemText(0));
556 void CFlightPlanComponent::loadFromDisk()
559 const QString fileName =
560 QFileDialog::getOpenFileName(
this, tr(
"Load flight plan"), this->getDefaultFilename(
true),
561 "Flight plans (*.json *.sfp *.vfp *.xml);;swift (*.json *.txt);;SimBrief "
562 "(*.xml);;vPilot (*.vfp);;SB4 (*.sfp)");
563 if (fileName.isEmpty()) {
return; }
564 CFlightPlan fp = CFlightPlan::loadFromMultipleFormats(fileName, &msgs);
570 this->updateDirectorySettings(fileName);
575 void CFlightPlanComponent::loadTemplateFromDisk()
577 const QFile f(this->getTemplateName());
578 if (!f.exists()) {
return; }
581 CFlightPlan fp = CFlightPlan::loadFromMultipleFormats(f.fileName(), &msgs);
586 void CFlightPlanComponent::saveToDisk()
589 const QString fileName = QFileDialog::getSaveFileName(
590 nullptr, tr(
"Save flight plan"), this->getDefaultFilename(
false), tr(
"swift (*.json;*.txt)"));
592 if (fileName.isEmpty())
594 m =
CStatusMessage(
this, CStatusMessage::SeverityDebug, u
"Save canceled",
true);
598 QFileInfo fi(fileName);
599 QDir fpDir = fi.absoluteDir();
600 if (CDirectoryUtils::isInApplicationDirectory(fpDir.absolutePath()))
603 QMessageBox::warning(
this,
"swift flight plan",
604 "You try to save inside the swift directory '" + fpDir.absolutePath() +
605 "'\n\nThis is not recommended!"
606 "\n\nDo you want to really do this?",
607 QMessageBox::Save | QMessageBox::Cancel);
608 if (ret != QMessageBox::Save) {
return; }
611 const bool ok = this->saveFPToDisk(fileName);
614 m =
CStatusMessage(
this, CStatusMessage::SeverityInfo, u
"Written " % fileName,
true);
615 this->updateDirectorySettings(fileName);
617 else { m =
CStatusMessage(
this, CStatusMessage::SeverityError, u
"Writing " % fileName % u
" failed",
true); }
620 if (m.
isFailure()) { CLogMessage::preformatted(m); }
623 bool CFlightPlanComponent::saveFPToDisk(
const QString &fileName)
631 const CVariant variantFp = CVariant::fromValue(fp);
633 const bool ok = CFileUtils::writeStringToFile(json, fileName);
638 void CFlightPlanComponent::saveTemplateToDisk()
640 const QString fn = this->getTemplateName();
641 const bool ok = this->saveFPToDisk(fn);
646 void CFlightPlanComponent::clearTemplate()
648 QFile f(this->getTemplateName());
649 if (!f.exists()) {
return; }
650 const bool r = f.remove();
651 if (r) {
CLogMessage(
this).
info(u
"Deleted FP template '%1'") << f.fileName(); }
654 QString CFlightPlanComponent::getTemplateName()
const
656 const QString fn = CFileUtils::appendFilePathsAndFixUnc(CSwiftDirectories::normalizedApplicationDataDirectory(),
657 QStringLiteral(
"swiftFlightPlanTemplate.json"));
661 void CFlightPlanComponent::setSelcalInOwnAircraft()
664 if (!ui->frp_SelcalCode->hasValidCode()) {
return; }
668 void CFlightPlanComponent::loadFlightPlanFromNetwork()
683 const QMessageBox::StandardButton r = QMessageBox::warning(
684 this,
"Loaded FP",
"Override current flight plan data?", QMessageBox::Yes | QMessageBox::No);
685 if (r != QMessageBox::Yes) {
return; }
696 void CFlightPlanComponent::buildRemarksString()
698 QString v = ui->cb_VoiceCapabilities->currentText().toUpper();
699 QString rem = CFlightPlanRemarks::textToVoiceCapabilitiesRemarks(v).append(
" ");
701 v = ui->le_AirlineOperator->text().trimmed();
702 if (!v.isEmpty()) rem.append(
"OPR/").append(v).append(
" ");
704 v = ui->le_AircraftRegistration->text().trimmed();
705 if (!v.isEmpty()) rem.append(
"REG/").append(v).append(
" ");
707 v = ui->cb_PilotRating->currentText().toUpper();
708 if (v.contains(
"P1")) { rem.append(
"PR/P1 "); }
709 else if (v.contains(
"P2")) { rem.append(
"PR/P2 "); }
710 else if (v.contains(
"P3")) { rem.append(
"PR/P3 "); }
711 else if (v.contains(
"P4")) { rem.append(
"PR/P4 "); }
712 else if (v.contains(
"P5")) { rem.append(
"PR/P5 "); }
714 v = ui->cb_RequiredNavigationPerformance->currentText().toUpper();
715 if (v.contains(
"10")) { rem.append(
"RNP10 "); }
716 else if (v.contains(
"4")) { rem.append(
"RNP4 "); }
718 v = ui->cb_PerformanceCategory->currentText().toUpper();
719 if (v.startsWith(
"A")) { rem.append(
"PER/A "); }
720 else if (v.startsWith(
"B")) { rem.append(
"PER/B "); }
721 else if (v.startsWith(
"C")) { rem.append(
"PER/C "); }
722 else if (v.startsWith(
"D")) { rem.append(
"PER/D "); }
723 else if (v.startsWith(
"E")) { rem.append(
"PER/E "); }
725 if (ui->frp_SelcalCode->hasValidCode())
727 rem.append(
"SEL/").append(ui->frp_SelcalCode->getSelcalCode());
731 if (ui->cb_NoSidsStarts->isChecked()) { rem.append(
"NO SID/STAR "); }
733 v = ui->pte_AdditionalRemarks->toPlainText().trimmed();
734 if (!v.isEmpty()) { rem.append(v); }
736 rem = rem.simplified().trimmed();
737 ui->pte_RemarksGenerated->setPlainText(rem);
740 void CFlightPlanComponent::copyRemarks(
bool confirm)
742 const QString generated = ui->pte_RemarksGenerated->toPlainText().trimmed();
743 if (confirm && !this->overrideRemarks()) {
return; }
744 ui->pte_Remarks->setPlainText(generated);
748 void CFlightPlanComponent::currentTabGenerator() { this->setCurrentWidget(ui->tb_RemarksGenerator); }
750 void CFlightPlanComponent::swiftWebDataRead() { this->initCompleters(); }
752 void CFlightPlanComponent::aircraftTypeChanged()
756 QPointer<CFlightPlanComponent> myself(
this);
759 updateWakeTurbulenceCategorySelector(icao.
getWtc());
763 void CFlightPlanComponent::syncWithSimulator()
766 const QMessageBox::StandardButton reply = QMessageBox::question(
767 this, QStringLiteral(
"Override aircraft data"),
768 QStringLiteral(
"Override aircraft ICAO data from simulator"), QMessageBox::Yes | QMessageBox::No);
769 if (reply != QMessageBox::Yes) {
return; }
772 this->prefillWithAircraftData(aircraft,
true);
777 const QString designator(ui->le_AircraftType->text());
778 if (!CAircraftIcaoCode::isValidDesignator(designator)) {
return CAircraftIcaoCode(); }
783 if (designatorFromDb.
isLoadedFromDb()) {
return designatorFromDb; }
788 bool CFlightPlanComponent::isVfr()
const
790 const bool vfr = CFlightPlan::isVFRRules(ui->cb_FlightRule->currentText());
800 bool CFlightPlanComponent::overrideRemarks()
802 if (!ui->pte_Remarks->toPlainText().trimmed().isEmpty())
804 const int reply = QMessageBox::question(
this,
"Remarks",
"Override existing remarks?",
805 QMessageBox::Yes | QMessageBox::No);
806 if (reply != QMessageBox::Yes) {
return false; }
811 void CFlightPlanComponent::updateDirectorySettings(
const QString &fileOrDirectory)
813 if (fileOrDirectory.isEmpty()) {
return; }
818 CLogMessage::preformatted(saveMsg);
821 void CFlightPlanComponent::altitudeDialog()
823 if (!m_altitudeDialog) { m_altitudeDialog =
new CAltitudeDialog(
this); }
825 const QDialog::DialogCode ret =
static_cast<QDialog::DialogCode
>(m_altitudeDialog->exec());
826 if (ret != QDialog::Accepted) {
return; }
834 void CFlightPlanComponent::updateRemarksHistories()
836 QString r = ui->pte_Remarks->toPlainText();
839 QStringList h = m_remarksHistory.get();
840 if (consolidateRemarks(h, r))
843 CLogMessage::preformatted(m);
847 r = ui->pte_AdditionalRemarks->toPlainText();
850 QStringList h = m_remarksHistoryAdditional.get();
851 if (consolidateRemarks(h, r))
854 CLogMessage::preformatted(m);
859 void CFlightPlanComponent::setRemarksUIValues(
const QString &remarks)
861 if (remarks.isEmpty()) {
return; }
863 if (remarks.contains(
"/V"))
868 else if (remarks.contains(
"/T"))
873 else if (remarks.contains(
"/R"))
879 const int selcal = remarks.indexOf(
"SEL/");
880 if (selcal >= 0 && remarks.length() > selcal + 7)
882 const QString code = remarks.mid(selcal + 4, 4);
883 if (code.length() == 4) { ui->frp_SelcalCode->setSelcal(code); }
887 void CFlightPlanComponent::loadFromSimBrief()
890 if (!m_simBriefDialog) { m_simBriefDialog =
new CSimBriefDownloadDialog(
this); }
891 const int rv = m_simBriefDialog->
exec();
892 if (rv != QDialog::Accepted) {
return; }
898 void CFlightPlanComponent::handleSimBriefResponse(QNetworkReply *nwReplyPtr)
902 QScopedPointer<QNetworkReply, QScopedPointerDeleteLater> nwReply(nwReplyPtr);
905 const QUrl url(nwReply->url());
906 const QString urlString(url.toString());
908 if (nwReply->error() == QNetworkReply::NoError)
911 const QString simBriefFP(nwReplyPtr->readAll());
916 CFlightPlan fp = CFlightPlan::fromSimBriefFormat(simBriefFP);
919 const QString currentVoiceCapability = ui->cb_VoiceCapabilities->currentText();
920 fp.
setVoiceCapabilities(CFlightPlanRemarks::textToVoiceCapabilitiesRemarks(currentVoiceCapability));
932 void CFlightPlanComponent::setupNavComContextMenu()
934 m_navComEquipmentMenu =
new QMenu(ui->tb_EditNavComEquipment);
935 auto list =
new QListWidget(m_navComEquipmentMenu);
936 list->setSelectionMode(QAbstractItemView::MultiSelection);
939 connect(list, &QListWidget::itemSelectionChanged,
this,
940 &CFlightPlanComponent::updateNavComEquipmentFromSelection);
942 auto action =
new QWidgetAction(ui->tb_EditNavComEquipment);
943 action->setDefaultWidget(list);
944 m_navComEquipmentMenu->addAction(action);
946 updateNavComEquipmentUi();
949 void CFlightPlanComponent::setupSsrContextMenu()
951 m_ssrEquipmentMenu =
new QMenu(ui->tb_EditSsrEquipment);
952 auto list =
new QListWidget(m_ssrEquipmentMenu);
953 list->setSelectionMode(QAbstractItemView::MultiSelection);
956 connect(list, &QListWidget::itemSelectionChanged,
this, &CFlightPlanComponent::updateSsrEquipmentFromSelection);
958 auto action =
new QWidgetAction(ui->tb_EditSsrEquipment);
959 action->setDefaultWidget(list);
960 m_ssrEquipmentMenu->addAction(action);
962 updateSsrEquipmentUi();
965 void CFlightPlanComponent::updateNavComEquipmentFromSelection()
967 const QListWidget *list = getMenuEquipmentList(m_navComEquipmentMenu);
969 QString equipmentString;
971 for (
auto equipment : list->selectedItems()) { equipmentString.append(equipment->text()); }
974 updateNavComEquipmentUi();
977 void CFlightPlanComponent::updateSsrEquipmentFromSelection()
979 const QListWidget *list = getMenuEquipmentList(m_ssrEquipmentMenu);
981 QString ssrEquipmentString;
983 for (
auto equipment : list->selectedItems()) { ssrEquipmentString.append(equipment->text()); }
986 updateSsrEquipmentUi();
989 QListWidget *CFlightPlanComponent::getMenuEquipmentList(QMenu *menu)
991 Q_ASSERT_X(menu->actions().size() == 1, Q_FUNC_INFO,
"should only contain a single action");
992 const QWidgetAction *action = qobject_cast<QWidgetAction *>(menu->actions().at(0));
993 Q_ASSERT_X(action, Q_FUNC_INFO,
"equipment menu contains invalid action item");
994 auto list = qobject_cast<QListWidget *>(action->defaultWidget());
995 Q_ASSERT_X(list, Q_FUNC_INFO,
"Action widget contains invalid widget");
999 void CFlightPlanComponent::updateSsrEquipmentUi()
1001 ui->le_SsrEquipment->setText(m_ssrEquipment.
toQString());
1002 updateListSelection(m_ssrEquipmentMenu, m_ssrEquipment.
enabledOptions());
1005 void CFlightPlanComponent::updateNavComEquipmentUi()
1007 ui->le_NavComEquipment->setText(m_navComEquipment.
toQString());
1008 updateListSelection(m_navComEquipmentMenu, m_navComEquipment.
enabledOptions());
1011 void CFlightPlanComponent::updateListSelection(QMenu *menu,
const QStringList &enabledOptions)
1013 QListWidget *list = getMenuEquipmentList(menu);
1014 list->blockSignals(
true);
1015 list->clearSelection();
1016 for (
const auto &enabledOption : enabledOptions)
1018 auto item = list->findItems(enabledOption, Qt::MatchExactly);
1019 Q_ASSERT_X(item.size() == 1, Q_FUNC_INFO,
"Expected exactly one item per option");
1020 item[0]->setSelected(
true);
1022 list->blockSignals(
false);
1025 void CFlightPlanComponent::updateWakeTurbulenceCategorySelector(
1029 const auto it = std::find_if(m_wakeTurbulenceCategories.cbegin(), m_wakeTurbulenceCategories.cend(),
1030 [&wtc](
const WakeTurbulenceEntry &item) { return item.m_wtc == wtc; });
1031 Q_ASSERT_X(it != m_wakeTurbulenceCategories.cend(), Q_FUNC_INFO,
"Invalid wake turbulence category selected");
1032 const int newIndex =
static_cast<int>(std::distance(m_wakeTurbulenceCategories.cbegin(), it));
1033 ui->cb_Wtc->setCurrentIndex(newIndex);
1038 return m_wakeTurbulenceCategories.at(ui->cb_Wtc->currentIndex()).m_wtc;
1041 bool CFlightPlanComponent::consolidateRemarks(QStringList &remarks,
const QString &newRemarks)
1043 if (newRemarks.isEmpty()) {
return false; }
1044 remarks.removeAll(newRemarks);
1045 remarks.push_front(newRemarks);
1049 void CFlightPlanComponent::remarksHistory()
1051 const QObject *sender = QObject::sender();
1052 if (!m_fpRemarksDialog)
1054 m_fpRemarksDialog =
new CStringListDialog(
this);
1055 m_fpRemarksDialog->setModal(
true);
1057 if (sender == ui->pb_Remarks) { m_fpRemarksDialog->
setStrings(m_remarksHistory.getThreadLocal()); }
1058 else if (sender == ui->pb_AddRemarks)
1060 m_fpRemarksDialog->
setStrings(m_remarksHistoryAdditional.getThreadLocal());
1063 const int rv = m_fpRemarksDialog->exec();
1064 if (rv != QDialog::Accepted) {
return; }
1066 if (remarks.isEmpty()) {
return; }
1068 if (sender == ui->pb_Remarks) { ui->pte_Remarks->setPlainText(remarks); }
1069 else if (sender == ui->pb_AddRemarks) { ui->pte_AdditionalRemarks->setPlainText(remarks); }
1072 void CFlightPlanComponent::initCompleters()
1076 QCompleter *aircraftCompleter =
new QCompleter(aircraft,
this);
1077 aircraftCompleter->setMaxVisibleItems(10);
1078 const int w5chars1 = aircraftCompleter->popup()->fontMetrics().size(Qt::TextSingleLine,
"FooBa").width();
1079 aircraftCompleter->popup()->setMinimumWidth(w5chars1 * 5);
1080 aircraftCompleter->setCaseSensitivity(Qt::CaseInsensitive);
1081 aircraftCompleter->setCompletionMode(QCompleter::PopupCompletion);
1082 ui->le_AircraftType->setCompleter(aircraftCompleter);
1085 QCompleter *airportCompleter =
new QCompleter(airports,
this);
1086 airportCompleter->setMaxVisibleItems(10);
1087 const int w5chars2 = airportCompleter->popup()->fontMetrics().size(Qt::TextSingleLine,
"FooBa").width();
1088 airportCompleter->popup()->setMinimumWidth(w5chars2 * 5);
1089 airportCompleter->setCaseSensitivity(Qt::CaseInsensitive);
1090 airportCompleter->setCompletionMode(QCompleter::PopupCompletion);
1091 ui->le_AlternateAirport->setCompleter(airportCompleter);
1092 ui->le_DestinationAirport->setCompleter(airportCompleter);
1093 ui->le_OriginAirport->setCompleter(airportCompleter);
1096 QString CFlightPlanComponent::getDefaultFilename(
bool load)
1099 const QString dir = m_directories.
get().getFlightPlanDirectoryOrDefault();
1100 if (load) {
return dir; }
1103 QString name(
"Flight plan");
1104 if (!ui->le_DestinationAirport->text().isEmpty() && !ui->le_OriginAirport->text().isEmpty())
1106 name += u
' ' % ui->le_OriginAirport->text() % u
'-' % ui->le_DestinationAirport->text();
1109 if (!name.endsWith(CFileUtils::jsonAppendix(), Qt::CaseInsensitive)) { name += CFileUtils::jsonAppendix(); }
1110 return CFileUtils::appendFilePaths(dir, name);
1113 void CFlightPlanComponent::syncVoiceComboBoxes(
const QString &text)
1115 const QObject *sender = QObject::sender();
1116 if (sender == ui->cb_VoiceCapabilities)
1118 const QString ct = ui->cb_VoiceCapabilitiesFirstPage->currentText();
1119 if (
stringCompare(ct, text, Qt::CaseInsensitive)) {
return; }
1120 ui->cb_VoiceCapabilitiesFirstPage->setCurrentText(text);
1124 const QString ct = ui->cb_VoiceCapabilities->currentText();
1128 ui->cb_VoiceCapabilities->setCurrentText(text);
1130 const QString r = CFlightPlanRemarks::replaceVoiceCapabilities(
1131 CFlightPlanRemarks::textToVoiceCapabilitiesRemarks(text), ui->pte_Remarks->toPlainText());
1132 if (ui->pte_Remarks->toPlainText() != r) { ui->pte_Remarks->setPlainText(r); }
SWIFT_CORE_EXPORT swift::core::CApplication * sApp
Single instance of application object.
QNetworkReply * getFromNetwork(const swift::misc::network::CUrl &url, const CallbackSlot &callback, int maxRedirects=DefaultMaxRedirects)
Request to get network reply.
const context::IContextOwnAircraft * getIContextOwnAircraft() const
Direct access to contexts if a CCoreFacade has been initialized.
bool hasWebDataServices() const
Web data services available?
const context::IContextNetwork * getIContextNetwork() const
Direct access to contexts if a CCoreFacade has been initialized.
bool isShuttingDown() const
Is application shutting down?
const context::IContextSimulator * getIContextSimulator() const
Direct access to contexts if a CCoreFacade has been initialized.
CWebDataServices * getWebDataServices() const
Get the web data services.
swift::misc::aviation::CAircraftIcaoCode getAircraftIcaoCodeForDesignator(const QString &designator) const
ICAO code for designator.
swift::misc::aviation::CAirportList getAirports() const
Get airports.
bool containsAircraftIcaoDesignator(const QString &designator) const
Contains the given designator?
bool hasDbAircraftData() const
Are all DB data for an aircraft entity available?
swift::misc::aviation::CAircraftIcaoCodeList getAircraftIcaoCodes() const
Aircraft ICAO codes.
virtual void sendFlightPlan(const swift::misc::aviation::CFlightPlan &flightPlan)=0
Send flight plan.
virtual swift::misc::aviation::CFlightPlan loadFlightPlanFromNetwork(const swift::misc::aviation::CCallsign &callsign) const =0
Load flight plan (from network)
virtual bool isConnected() const =0
Network connected?
virtual bool updateSelcal(const swift::misc::aviation::CSelcal &selcal, const swift::misc::CIdentifier &originator)=0
Own SELCAL code.
virtual swift::misc::simulation::CSimulatedAircraft getOwnAircraft() const =0
Get own aircraft.
bool isSimulatorAvailable() const
Simulator avialable (driver available)?
static bool setComboBoxValueByContainingString(QComboBox *box, const QString &candidate, const QString &unspecified=QString())
Find best match in comboBox.
bool showOverlayHTMLMessage(const QString &htmlMessage, std::chrono::milliseconds timeout=std::chrono::milliseconds(0))
HTML message.
bool showOverlayMessage(const swift::misc::CStatusMessage &message, std::chrono::milliseconds timeout=std::chrono::milliseconds(0))
Show single message.
void showOverlayMessages(const swift::misc::CStatusMessageList &messages, bool appendOldMessages=false, std::chrono::milliseconds timeout=std::chrono::milliseconds(0))
Show multiple messages.
void setForceSmall(bool force)
Force small (smaller layout)
void setOverlaySizeFactors(double widthFactor, double heightFactor, double middleFactor=2)
Set the size factors.
void setReducedInfo(bool reduced)
Display reduced information.
const QString & getAltitudeString() const
Altitude string.
virtual ~CFlightPlanComponent()
Destructor.
static const QStringList & getLogCategories()
Log.categories.
void fillWithFlightPlanData(const swift::misc::aviation::CFlightPlan &flightPlan)
Prefill with aircraft dara.
void loginDataSet()
Login data were set.
void valueChanged()
Value has been changed.
swift::misc::aviation::CSimBriefData getSimBriefData() const
SimBrief data.
QString getSelectedValue() const
Selected value.
void setStrings(const QStringList &strings)
Strings.
CStatusMessage setAndSave(const T &value, qint64 timestamp=0)
Write and save in the same step. Must be called from the thread in which the owner lives.
T get() const
Get a copy of the current value.
Directories (swift data directories)
void setFlightPlanDirectory(const QString &dir)
Flight plan directory.
Class for emitting a log message.
Derived & warning(const char16_t(&format)[N])
Set the severity to warning, providing a format string.
Derived & validationError(const char16_t(&format)[N])
Set the severity to error, providing a format string, and adding the validation category.
Derived & validationWarning(const char16_t(&format)[N])
Set the severity to warning, providing a format string, and adding the validation category.
Derived & validationInfo(const char16_t(&format)[N])
Set the severity to info, providing a format string, and adding the validation category.
Derived & info(const char16_t(&format)[N])
Set the severity to info, providing a format string.
void push_back(const T &value)
Appends an element at the end of the sequence.
Streamable status message, e.g.
bool isSeverityInfoOrLess() const
Info or debug, no warning or error.
bool isFailure() const
Operation considered unsuccessful.
Status messages, e.g. from Core -> GUI.
bool isFailure() const
Any message is marked as failure.
bool hasWarningOrErrorMessages() const
Warning or error messages.
bool isSuccess() const
All messages are marked as success.
Wrapper around QVariant which provides transparent access to CValueObject methods of the contained ob...
QString toJsonString(QJsonDocument::JsonFormat format=QJsonDocument::Indented) const
Convenience function JSON as string.
Value object for ICAO classification.
CWakeTurbulenceCategory getWtc() const
Get WTC.
bool hasValidWtc() const
Valid WTC code?
QSet< QString > allDesignators(bool noUnspecified=true) const
All ICAO codes, no duplicates.
bool hasValidIcaoCode(bool strict) const
Has valid code?
QString getIcaoCode() const
Get ICAO code.
const QString & asString() const
Get code.
QStringList allIcaoCodes(bool sorted) const
All ICAO codes.
Altitude as used in aviation, can be AGL or MSL altitude.
Value object encapsulating information of a callsign.
const QString & asString() const
Get callsign (normalized)
ICAO flightplan field 10a.
QStringList enabledOptions() const
Get all enabled equipment codes of this object as a list.
static QStringList allEquipmentLetters()
Get all possible equipment code letters.
Flightplan-related information about an aircraft (aircraft ICAO, equipment and WTC)
CWakeTurbulenceCategory getWtc() const
Get Wake Turbulence Category.
CSsrEquipment getSsrEquipment() const
Get SSR equipment.
CComNavEquipment getComNavEquipment() const
Get COM/NAV equipment.
Value object for a flight plan.
void setAircraftInfo(const CFlightPlanAircraftInfo &aircraftInfo)
Set information about the aircraft used in this flightplan.
bool wasSentOrLoaded() const
Flight plan already sent.
QString getFlightRulesAsString() const
Get flight rules as in FlightRules as string.
void setFlightRule(FlightRules flightRule)
Set flight rules (VFR or IFR)
QString getFuelTimeHourMin() const
Get amount of fuel load in time.
QString getTakeoffTimePlannedHourMin() const
Get planned takeoff time (planned)
const physical_quantities::CSpeed & getCruiseTrueAirspeed() const
Get planned cruise TAS.
void setVoiceCapabilities(const QString &capabilities)
Set voice capabilities.
void setOriginAirportIcao(const QString &originAirportIcao)
Set origin airport ICAO code.
void setTakeoffTimePlanned(const QDateTime &takeoffTimePlanned)
Set planned takeoff time.
void setCruiseTrueAirspeed(const physical_quantities::CSpeed &cruiseTrueAirspeed)
Set planned cruise TAS.
void setAlternateAirportIcao(const QString &alternateAirportIcao)
Set alternate destination airport ICAO code.
void setFuelTime(const physical_quantities::CTime &fuelTime)
Set amount of fuel load in time.
const QString & getRoute() const
Get route string.
FlightRules
Flight rules (VFR or IFR)
FlightRules getFlightRules() const
Get flight rules as in FlightRules.
const QString & getRemarks() const
Get remarks string.
bool hasCallsign() const
Has callsign?
QString getEnrouteTimeHourMin() const
Get planned enroute flight time.
const CAirportIcaoCode & getAlternateAirportIcao() const
Get alternate destination airport ICAO code.
const CAltitude & getCruiseAltitude() const
Cruising altitudes.
void setRemarks(const QString &remarks)
Set remarks string (max 100 characters)
void setEnrouteTime(const physical_quantities::CTime &enrouteTime)
Set planned enroute flight time.
const CAirportIcaoCode & getOriginAirportIcao() const
Get origin airport ICAO code.
const QDateTime whenLastSentOrLoaded() const
When last sent.
void setRoute(const QString &route)
Set route string.
void setWhenLastSentOrLoaded(const QDateTime &dateTime)
When last sent.
const CAirportIcaoCode & getDestinationAirportIcao() const
Get destination airport ICAO code.
void setDestinationAirportIcao(const QString &destinationAirportIcao)
Set destination airport ICAO code.
void setCruiseAltitude(const CAltitude &cruiseAltitude)
Set planned cruise altitude.
CFlightPlanAircraftInfo getAircraftInfo() const
Get ICAO aircraft NAV/COM equipment.
void setCallsign(const CCallsign &callsign)
Callsign (of aircraft)
network::CUrl getUrlAndUsername() const
Get URL plus username.
ICAO flightplan field 10b.
QStringList enabledOptions() const
Get all enabled SSR equipment codes of this object as a list.
static QStringList allEquipmentLetters()
Get all possible SSR equipment code letters.
ICAO wake turbulence category.
bool isUnknown() const
Is the wake turbulence category unknown?
bool isLoadedFromDb() const
Loaded from DB.
QString toQString(bool i18n=false) const
Cast as QString.
Value object encapsulating information of a location, kind of simplified CValueObject compliant versi...
QNetworkRequest toNetworkRequest() const
To request.
Value object encapsulating information of a user.
const aviation::CAirportIcaoCode & getHomeBase() const
Homebase.
bool hasRealName() const
Valid real name?
const QString & getRealName() const
Get full name.
const aviation::CCallsign & getCallsign() const
Get associated callsign.
bool hasHomeBase() const
Has home base?
bool hasCallsign() const
Has associated callsign?
void parseFromString(const QString &value)
Parse value from string.
bool isNull() const
Is quantity null?
QString valueRoundedWithUnit(const MU &unit, int digits=-1, bool withGroupSeparator=false, bool i18n=false) const
Value to QString with the given unit, e.g. "5.00m".
Comprehensive information of an aircraft.
const network::CUser & getPilot() const
Get user.
const aviation::CCallsign & getCallsign() const
Get callsign.
const aviation::CAircraftIcaoCode & getAircraftIcaoCode() const
Get aircraft ICAO info.
const QString & getAircraftIcaoCodeDesignator() const
Aircraft ICAO code designator.
const simulation::CAircraftModel & getModel() const
Get model (model used for mapping)
QString getCallsignAsString() const
Get callsign.
SWIFT_GUI_EXPORT swift::gui::CGuiApplication * sGui
Single instance of GUI application object.
Backend services of the swift project, like dealing with the network or the simulators.
High level reusable GUI components.
Free functions in swift::misc.
SWIFT_MISC_EXPORT bool stringCompare(const QString &c1, const QString &c2, Qt::CaseSensitivity cs)
String compare.
auto singleShot(int msec, QObject *target, F &&task)
Starts a single-shot timer which will call a task in the thread of the given object when it times out...