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 = QFileDialog::getOpenFileName(
560 this, tr(
"Load flight plan"), this->getDefaultFilename(
true),
561 "Flight plans (*.json *.sfp *.xml);;swift (*.json *.txt);;SimBrief (*.xml);;SB4 (*.sfp)");
562 if (fileName.isEmpty()) {
return; }
563 CFlightPlan fp = CFlightPlan::loadFromMultipleFormats(fileName, &msgs);
569 this->updateDirectorySettings(fileName);
574 void CFlightPlanComponent::loadTemplateFromDisk()
576 const QFile f(this->getTemplateName());
577 if (!f.exists()) {
return; }
580 CFlightPlan fp = CFlightPlan::loadFromMultipleFormats(f.fileName(), &msgs);
585 void CFlightPlanComponent::saveToDisk()
588 const QString fileName = QFileDialog::getSaveFileName(
589 nullptr, tr(
"Save flight plan"), this->getDefaultFilename(
false), tr(
"swift (*.json;*.txt)"));
591 if (fileName.isEmpty())
593 m =
CStatusMessage(
this, CStatusMessage::SeverityDebug, u
"Save canceled",
true);
597 QFileInfo fi(fileName);
598 QDir fpDir = fi.absoluteDir();
599 if (CDirectoryUtils::isInApplicationDirectory(fpDir.absolutePath()))
602 QMessageBox::warning(
this,
"swift flight plan",
603 "You try to save inside the swift directory '" + fpDir.absolutePath() +
604 "'\n\nThis is not recommended!"
605 "\n\nDo you want to really do this?",
606 QMessageBox::Save | QMessageBox::Cancel);
607 if (ret != QMessageBox::Save) {
return; }
610 const bool ok = this->saveFPToDisk(fileName);
613 m =
CStatusMessage(
this, CStatusMessage::SeverityInfo, u
"Written " % fileName,
true);
614 this->updateDirectorySettings(fileName);
616 else { m =
CStatusMessage(
this, CStatusMessage::SeverityError, u
"Writing " % fileName % u
" failed",
true); }
619 if (m.
isFailure()) { CLogMessage::preformatted(m); }
622 bool CFlightPlanComponent::saveFPToDisk(
const QString &fileName)
630 const CVariant variantFp = CVariant::fromValue(fp);
632 const bool ok = CFileUtils::writeStringToFile(json, fileName);
637 void CFlightPlanComponent::saveTemplateToDisk()
639 const QString fn = this->getTemplateName();
640 const bool ok = this->saveFPToDisk(fn);
645 void CFlightPlanComponent::clearTemplate()
647 QFile f(this->getTemplateName());
648 if (!f.exists()) {
return; }
649 const bool r = f.remove();
650 if (r) {
CLogMessage(
this).
info(u
"Deleted FP template '%1'") << f.fileName(); }
653 QString CFlightPlanComponent::getTemplateName()
const
655 const QString fn = CFileUtils::appendFilePathsAndFixUnc(CSwiftDirectories::normalizedApplicationDataDirectory(),
656 QStringLiteral(
"swiftFlightPlanTemplate.json"));
660 void CFlightPlanComponent::setSelcalInOwnAircraft()
663 if (!ui->frp_SelcalCode->hasValidCode()) {
return; }
667 void CFlightPlanComponent::loadFlightPlanFromNetwork()
682 const QMessageBox::StandardButton r = QMessageBox::warning(
683 this,
"Loaded FP",
"Override current flight plan data?", QMessageBox::Yes | QMessageBox::No);
684 if (r != QMessageBox::Yes) {
return; }
695 void CFlightPlanComponent::buildRemarksString()
697 QString v = ui->cb_VoiceCapabilities->currentText().toUpper();
698 QString rem = CFlightPlanRemarks::textToVoiceCapabilitiesRemarks(v).append(
" ");
700 v = ui->le_AirlineOperator->text().trimmed();
701 if (!v.isEmpty()) rem.append(
"OPR/").append(v).append(
" ");
703 v = ui->le_AircraftRegistration->text().trimmed();
704 if (!v.isEmpty()) rem.append(
"REG/").append(v).append(
" ");
706 v = ui->cb_PilotRating->currentText().toUpper();
707 if (v.contains(
"P1")) { rem.append(
"PR/P1 "); }
708 else if (v.contains(
"P2")) { rem.append(
"PR/P2 "); }
709 else if (v.contains(
"P3")) { rem.append(
"PR/P3 "); }
710 else if (v.contains(
"P4")) { rem.append(
"PR/P4 "); }
711 else if (v.contains(
"P5")) { rem.append(
"PR/P5 "); }
713 v = ui->cb_RequiredNavigationPerformance->currentText().toUpper();
714 if (v.contains(
"10")) { rem.append(
"RNP10 "); }
715 else if (v.contains(
"4")) { rem.append(
"RNP4 "); }
717 v = ui->cb_PerformanceCategory->currentText().toUpper();
718 if (v.startsWith(
"A")) { rem.append(
"PER/A "); }
719 else if (v.startsWith(
"B")) { rem.append(
"PER/B "); }
720 else if (v.startsWith(
"C")) { rem.append(
"PER/C "); }
721 else if (v.startsWith(
"D")) { rem.append(
"PER/D "); }
722 else if (v.startsWith(
"E")) { rem.append(
"PER/E "); }
724 if (ui->frp_SelcalCode->hasValidCode())
726 rem.append(
"SEL/").append(ui->frp_SelcalCode->getSelcalCode());
730 if (ui->cb_NoSidsStarts->isChecked()) { rem.append(
"NO SID/STAR "); }
732 v = ui->pte_AdditionalRemarks->toPlainText().trimmed();
733 if (!v.isEmpty()) { rem.append(v); }
735 rem = rem.simplified().trimmed();
736 ui->pte_RemarksGenerated->setPlainText(rem);
739 void CFlightPlanComponent::copyRemarks(
bool confirm)
741 const QString generated = ui->pte_RemarksGenerated->toPlainText().trimmed();
742 if (confirm && !this->overrideRemarks()) {
return; }
743 ui->pte_Remarks->setPlainText(generated);
747 void CFlightPlanComponent::currentTabGenerator() { this->setCurrentWidget(ui->tb_RemarksGenerator); }
749 void CFlightPlanComponent::swiftWebDataRead() { this->initCompleters(); }
751 void CFlightPlanComponent::aircraftTypeChanged()
755 QPointer<CFlightPlanComponent> myself(
this);
758 updateWakeTurbulenceCategorySelector(icao.
getWtc());
762 void CFlightPlanComponent::syncWithSimulator()
765 const QMessageBox::StandardButton reply = QMessageBox::question(
766 this, QStringLiteral(
"Override aircraft data"),
767 QStringLiteral(
"Override aircraft ICAO data from simulator"), QMessageBox::Yes | QMessageBox::No);
768 if (reply != QMessageBox::Yes) {
return; }
771 this->prefillWithAircraftData(aircraft,
true);
776 const QString designator(ui->le_AircraftType->text());
777 if (!CAircraftIcaoCode::isValidDesignator(designator)) {
return CAircraftIcaoCode(); }
782 if (designatorFromDb.
isLoadedFromDb()) {
return designatorFromDb; }
787 bool CFlightPlanComponent::isVfr()
const
789 const bool vfr = CFlightPlan::isVFRRules(ui->cb_FlightRule->currentText());
799 bool CFlightPlanComponent::overrideRemarks()
801 if (!ui->pte_Remarks->toPlainText().trimmed().isEmpty())
803 const int reply = QMessageBox::question(
this,
"Remarks",
"Override existing remarks?",
804 QMessageBox::Yes | QMessageBox::No);
805 if (reply != QMessageBox::Yes) {
return false; }
810 void CFlightPlanComponent::updateDirectorySettings(
const QString &fileOrDirectory)
812 if (fileOrDirectory.isEmpty()) {
return; }
817 CLogMessage::preformatted(saveMsg);
820 void CFlightPlanComponent::altitudeDialog()
822 if (!m_altitudeDialog) { m_altitudeDialog =
new CAltitudeDialog(
this); }
824 const QDialog::DialogCode ret =
static_cast<QDialog::DialogCode
>(m_altitudeDialog->exec());
825 if (ret != QDialog::Accepted) {
return; }
833 void CFlightPlanComponent::updateRemarksHistories()
835 QString r = ui->pte_Remarks->toPlainText();
838 QStringList h = m_remarksHistory.get();
839 if (consolidateRemarks(h, r))
842 CLogMessage::preformatted(m);
846 r = ui->pte_AdditionalRemarks->toPlainText();
849 QStringList h = m_remarksHistoryAdditional.get();
850 if (consolidateRemarks(h, r))
853 CLogMessage::preformatted(m);
858 void CFlightPlanComponent::setRemarksUIValues(
const QString &remarks)
860 if (remarks.isEmpty()) {
return; }
862 if (remarks.contains(
"/V"))
867 else if (remarks.contains(
"/T"))
872 else if (remarks.contains(
"/R"))
878 const int selcal = remarks.indexOf(
"SEL/");
879 if (selcal >= 0 && remarks.length() > selcal + 7)
881 const QString code = remarks.mid(selcal + 4, 4);
882 if (code.length() == 4) { ui->frp_SelcalCode->setSelcal(code); }
886 void CFlightPlanComponent::loadFromSimBrief()
889 if (!m_simBriefDialog) { m_simBriefDialog =
new CSimBriefDownloadDialog(
this); }
890 const int rv = m_simBriefDialog->
exec();
891 if (rv != QDialog::Accepted) {
return; }
897 void CFlightPlanComponent::handleSimBriefResponse(QNetworkReply *nwReplyPtr)
901 QScopedPointer<QNetworkReply, QScopedPointerDeleteLater> nwReply(nwReplyPtr);
904 const QUrl url(nwReply->url());
905 const QString urlString(url.toString());
907 if (nwReply->error() == QNetworkReply::NoError)
910 const QString simBriefFP(nwReplyPtr->readAll());
915 CFlightPlan fp = CFlightPlan::fromSimBriefFormat(simBriefFP);
918 const QString currentVoiceCapability = ui->cb_VoiceCapabilities->currentText();
919 fp.
setVoiceCapabilities(CFlightPlanRemarks::textToVoiceCapabilitiesRemarks(currentVoiceCapability));
931 void CFlightPlanComponent::setupNavComContextMenu()
933 m_navComEquipmentMenu =
new QMenu(ui->tb_EditNavComEquipment);
934 auto list =
new QListWidget(m_navComEquipmentMenu);
935 list->setSelectionMode(QAbstractItemView::MultiSelection);
938 connect(list, &QListWidget::itemSelectionChanged,
this,
939 &CFlightPlanComponent::updateNavComEquipmentFromSelection);
941 auto action =
new QWidgetAction(ui->tb_EditNavComEquipment);
942 action->setDefaultWidget(list);
943 m_navComEquipmentMenu->addAction(action);
945 updateNavComEquipmentUi();
948 void CFlightPlanComponent::setupSsrContextMenu()
950 m_ssrEquipmentMenu =
new QMenu(ui->tb_EditSsrEquipment);
951 auto list =
new QListWidget(m_ssrEquipmentMenu);
952 list->setSelectionMode(QAbstractItemView::MultiSelection);
955 connect(list, &QListWidget::itemSelectionChanged,
this, &CFlightPlanComponent::updateSsrEquipmentFromSelection);
957 auto action =
new QWidgetAction(ui->tb_EditSsrEquipment);
958 action->setDefaultWidget(list);
959 m_ssrEquipmentMenu->addAction(action);
961 updateSsrEquipmentUi();
964 void CFlightPlanComponent::updateNavComEquipmentFromSelection()
966 const QListWidget *list = getMenuEquipmentList(m_navComEquipmentMenu);
968 QString equipmentString;
970 for (
auto equipment : list->selectedItems()) { equipmentString.append(equipment->text()); }
973 updateNavComEquipmentUi();
976 void CFlightPlanComponent::updateSsrEquipmentFromSelection()
978 const QListWidget *list = getMenuEquipmentList(m_ssrEquipmentMenu);
980 QString ssrEquipmentString;
982 for (
auto equipment : list->selectedItems()) { ssrEquipmentString.append(equipment->text()); }
985 updateSsrEquipmentUi();
988 QListWidget *CFlightPlanComponent::getMenuEquipmentList(QMenu *menu)
990 Q_ASSERT_X(menu->actions().size() == 1, Q_FUNC_INFO,
"should only contain a single action");
991 const QWidgetAction *action = qobject_cast<QWidgetAction *>(menu->actions().at(0));
992 Q_ASSERT_X(action, Q_FUNC_INFO,
"equipment menu contains invalid action item");
993 auto list = qobject_cast<QListWidget *>(action->defaultWidget());
994 Q_ASSERT_X(list, Q_FUNC_INFO,
"Action widget contains invalid widget");
998 void CFlightPlanComponent::updateSsrEquipmentUi()
1000 ui->le_SsrEquipment->setText(m_ssrEquipment.
toQString());
1001 updateListSelection(m_ssrEquipmentMenu, m_ssrEquipment.
enabledOptions());
1004 void CFlightPlanComponent::updateNavComEquipmentUi()
1006 ui->le_NavComEquipment->setText(m_navComEquipment.
toQString());
1007 updateListSelection(m_navComEquipmentMenu, m_navComEquipment.
enabledOptions());
1010 void CFlightPlanComponent::updateListSelection(QMenu *menu,
const QStringList &enabledOptions)
1012 QListWidget *list = getMenuEquipmentList(menu);
1013 list->blockSignals(
true);
1014 list->clearSelection();
1015 for (
const auto &enabledOption : enabledOptions)
1017 auto item = list->findItems(enabledOption, Qt::MatchExactly);
1018 Q_ASSERT_X(item.size() == 1, Q_FUNC_INFO,
"Expected exactly one item per option");
1019 item[0]->setSelected(
true);
1021 list->blockSignals(
false);
1024 void CFlightPlanComponent::updateWakeTurbulenceCategorySelector(
1028 const auto it = std::find_if(m_wakeTurbulenceCategories.cbegin(), m_wakeTurbulenceCategories.cend(),
1029 [&wtc](
const WakeTurbulenceEntry &item) { return item.m_wtc == wtc; });
1030 Q_ASSERT_X(it != m_wakeTurbulenceCategories.cend(), Q_FUNC_INFO,
"Invalid wake turbulence category selected");
1031 const int newIndex =
static_cast<int>(std::distance(m_wakeTurbulenceCategories.cbegin(), it));
1032 ui->cb_Wtc->setCurrentIndex(newIndex);
1037 return m_wakeTurbulenceCategories.at(ui->cb_Wtc->currentIndex()).m_wtc;
1040 bool CFlightPlanComponent::consolidateRemarks(QStringList &remarks,
const QString &newRemarks)
1042 if (newRemarks.isEmpty()) {
return false; }
1043 remarks.removeAll(newRemarks);
1044 remarks.push_front(newRemarks);
1048 void CFlightPlanComponent::remarksHistory()
1050 const QObject *sender = QObject::sender();
1051 if (!m_fpRemarksDialog)
1053 m_fpRemarksDialog =
new CStringListDialog(
this);
1054 m_fpRemarksDialog->setModal(
true);
1056 if (sender == ui->pb_Remarks) { m_fpRemarksDialog->
setStrings(m_remarksHistory.getThreadLocal()); }
1057 else if (sender == ui->pb_AddRemarks)
1059 m_fpRemarksDialog->
setStrings(m_remarksHistoryAdditional.getThreadLocal());
1062 const int rv = m_fpRemarksDialog->exec();
1063 if (rv != QDialog::Accepted) {
return; }
1065 if (remarks.isEmpty()) {
return; }
1067 if (sender == ui->pb_Remarks) { ui->pte_Remarks->setPlainText(remarks); }
1068 else if (sender == ui->pb_AddRemarks) { ui->pte_AdditionalRemarks->setPlainText(remarks); }
1071 void CFlightPlanComponent::initCompleters()
1075 QCompleter *aircraftCompleter =
new QCompleter(aircraft,
this);
1076 aircraftCompleter->setMaxVisibleItems(10);
1077 const int w5chars1 = aircraftCompleter->popup()->fontMetrics().size(Qt::TextSingleLine,
"FooBa").width();
1078 aircraftCompleter->popup()->setMinimumWidth(w5chars1 * 5);
1079 aircraftCompleter->setCaseSensitivity(Qt::CaseInsensitive);
1080 aircraftCompleter->setCompletionMode(QCompleter::PopupCompletion);
1081 ui->le_AircraftType->setCompleter(aircraftCompleter);
1084 QCompleter *airportCompleter =
new QCompleter(airports,
this);
1085 airportCompleter->setMaxVisibleItems(10);
1086 const int w5chars2 = airportCompleter->popup()->fontMetrics().size(Qt::TextSingleLine,
"FooBa").width();
1087 airportCompleter->popup()->setMinimumWidth(w5chars2 * 5);
1088 airportCompleter->setCaseSensitivity(Qt::CaseInsensitive);
1089 airportCompleter->setCompletionMode(QCompleter::PopupCompletion);
1090 ui->le_AlternateAirport->setCompleter(airportCompleter);
1091 ui->le_DestinationAirport->setCompleter(airportCompleter);
1092 ui->le_OriginAirport->setCompleter(airportCompleter);
1095 QString CFlightPlanComponent::getDefaultFilename(
bool load)
1098 const QString dir = m_directories.
get().getFlightPlanDirectoryOrDefault();
1099 if (load) {
return dir; }
1102 QString name(
"Flight plan");
1103 if (!ui->le_DestinationAirport->text().isEmpty() && !ui->le_OriginAirport->text().isEmpty())
1105 name += u
' ' % ui->le_OriginAirport->text() % u
'-' % ui->le_DestinationAirport->text();
1108 if (!name.endsWith(CFileUtils::jsonAppendix(), Qt::CaseInsensitive)) { name += CFileUtils::jsonAppendix(); }
1109 return CFileUtils::appendFilePaths(dir, name);
1112 void CFlightPlanComponent::syncVoiceComboBoxes(
const QString &text)
1114 const QObject *sender = QObject::sender();
1115 if (sender == ui->cb_VoiceCapabilities)
1117 const QString ct = ui->cb_VoiceCapabilitiesFirstPage->currentText();
1118 if (
stringCompare(ct, text, Qt::CaseInsensitive)) {
return; }
1119 ui->cb_VoiceCapabilitiesFirstPage->setCurrentText(text);
1123 const QString ct = ui->cb_VoiceCapabilities->currentText();
1127 ui->cb_VoiceCapabilities->setCurrentText(text);
1129 const QString r = CFlightPlanRemarks::replaceVoiceCapabilities(
1130 CFlightPlanRemarks::textToVoiceCapabilitiesRemarks(text), ui->pte_Remarks->toPlainText());
1131 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...