From c08e0ec372e3ed50f5a56b49f6a394dfbd7cad83 Mon Sep 17 00:00:00 2001 From: Alexander Barthel Date: Mon, 26 Aug 2019 16:13:47 +0200 Subject: [PATCH] Added separate export menu item for X-IvAp since format differs slightly from IvAp. Fixed small isses with export format. Alternate airports are now pre-filled in online format export. Now setting dialog window titles using export format. closes #395 --- src/gui/mainwindow.cpp | 2 + src/gui/mainwindow.ui | 18 +++++- src/route/route.cpp | 22 ++++--- src/route/route.h | 8 ++- src/route/routeexport.cpp | 111 +++++++++++++++++++++++--------- src/route/routeexport.h | 9 ++- src/route/routeexportdialog.cpp | 70 ++++++++++++++++---- src/route/routeexportdialog.h | 7 +- 8 files changed, 188 insertions(+), 59 deletions(-) diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index 47eae39c1..310895b8b 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -1190,6 +1190,7 @@ void MainWindow::connectAllSlots() // Online export options connect(ui->actionRouteSaveAsVfp, &QAction::triggered, routeExport, &RouteExport::routeExportVfp); connect(ui->actionRouteSaveAsIvap, &QAction::triggered, routeExport, &RouteExport::routeExportIvap); + connect(ui->actionRouteSaveAsXIvap, &QAction::triggered, routeExport, &RouteExport::routeExportXIvap); connect(routeFileHistory, &FileHistoryHandler::fileSelected, this, &MainWindow::routeOpenRecent); @@ -3372,6 +3373,7 @@ void MainWindow::updateActionStates() ui->actionRouteSaveAsVfp->setEnabled(hasFlightplan); ui->actionRouteSaveAsIvap->setEnabled(hasFlightplan); + ui->actionRouteSaveAsXIvap->setEnabled(hasFlightplan); ui->actionRouteShowSkyVector->setEnabled(hasFlightplan); ui->actionRouteCenter->setEnabled(hasFlightplan); diff --git a/src/gui/mainwindow.ui b/src/gui/mainwindow.ui index 4b3032a56..37c269727 100644 --- a/src/gui/mainwindow.ui +++ b/src/gui/mainwindow.ui @@ -95,6 +95,7 @@ + @@ -10247,13 +10248,13 @@ relation to shown airport - Export Flight Plan as &IvAp or X-IvAp FPL ... + Export Flight Plan as &IvAp FPL ... - Save flight plan as FPL file for IvAp or X-IvAp + Save flight plan as FPL file for IvAp - Save flight plan as FPL file for IvAp or X-IvAp + Save flight plan as FPL file for IvAp @@ -10879,6 +10880,17 @@ relation to shown airport Hide or show columns in table + + + Export Flight Plan as X-IvAp FPL ... + + + Save flight plan as FPL file for X-IvAp + + + Save flight plan as FPL file for X-IvAp + + diff --git a/src/route/route.cpp b/src/route/route.cpp index 291d1c40d..0bc9941b7 100644 --- a/src/route/route.cpp +++ b/src/route/route.cpp @@ -233,11 +233,6 @@ bool Route::isSmaller(const atools::geo::LineDistance& dist1, const atools::geo: return std::abs(dist1.distance) < std::abs(dist2.distance) + epsilon; } -void Route::updateActivePos(const map::PosCourse& pos) -{ - activePos = pos; -} - void Route::updateActiveLegAndPos(const map::PosCourse& pos) { if(isEmpty() || !pos.isValid()) @@ -1011,10 +1006,7 @@ void Route::updateAlternateProperties() int offset = getAlternateLegsOffset(); if(offset != map::INVALID_INDEX_VALUE) { - QStringList alternates; - for(int idx = offset; idx < offset + getNumAlternateLegs(); idx++) - alternates.append(at(idx).getIdent()); - + QStringList alternates = getAlternateIdents(); if(!alternates.isEmpty()) getFlightplan().getProperties().insert(atools::fs::pln::ALTERNATES, alternates.join("#")); else @@ -1024,6 +1016,18 @@ void Route::updateAlternateProperties() getFlightplan().getProperties().remove(atools::fs::pln::ALTERNATES); } +QStringList Route::getAlternateIdents() const +{ + QStringList alternates; + int offset = getAlternateLegsOffset(); + if(offset != map::INVALID_INDEX_VALUE) + { + for(int idx = offset; idx < offset + getNumAlternateLegs(); idx++) + alternates.append(at(idx).getIdent()); + } + return alternates; +} + QBitArray Route::getJetAirwayFlags() const { QBitArray flags(size()); diff --git a/src/route/route.h b/src/route/route.h index 295cdc57f..d0e274cb4 100644 --- a/src/route/route.h +++ b/src/route/route.h @@ -529,13 +529,19 @@ class Route : void clearFlightplanAlternateProperties(); + /* Get ICAO idents of all alternates */ + QStringList getAlternateIdents() const; void updateAlternateProperties(); /* Get a bit array which indicates high/low airways - needed for some export formats. * True indicates high airway used towards waypoint at the same index. */ QBitArray getJetAirwayFlags() const; - void updateActivePos(const map::PosCourse& pos); + /* Update current position only */ + void updateActivePos(const map::PosCourse& pos) + { + activePos = pos; + } private: /* Remove any waypoints which positions overlap with procedures. Requires a flight plan that is cleaned up and contains diff --git a/src/route/routeexport.cpp b/src/route/routeexport.cpp index 5fb3ee94a..8c18eb675 100644 --- a/src/route/routeexport.cpp +++ b/src/route/routeexport.cpp @@ -670,27 +670,39 @@ bool RouteExport::routeExportVfp() return false; } +bool RouteExport::routeExportXIvap() +{ + return routeExportIvapInternal(re::XIVAP); +} + bool RouteExport::routeExportIvap() +{ + return routeExportIvapInternal(re::IVAP); +} + +bool RouteExport::routeExportIvapInternal(re::RouteExportType type) { qDebug() << Q_FUNC_INFO; if(routeValidate(false /* validate parking */, true /* validate departure and destination */)) { - RouteExportData exportData = createRouteExportData(re::IVAP); - if(routeExportDialog(exportData, re::IVAP)) + RouteExportData exportData = createRouteExportData(type); + if(routeExportDialog(exportData, type)) { + QString typeStr = RouteExportDialog::getRouteTypeAsDisplayString(type); QString routeFile = dialog->saveFileDialog( - tr("Export Flight Plan as IvAp/X-IvAp FPL"), - tr("FPL Files %1;;All Files (*)").arg(lnm::FILE_PATTERN_FPL), "fpl", "Route/Ivap", + tr("Export Flight Plan as %1 FPL").arg(typeStr), + tr("FPL Files %1;;All Files (*)").arg(lnm::FILE_PATTERN_FPL), "fpl", + "Route/" + RouteExportDialog::getRouteTypeAsString(type), documentsLocation, buildDefaultFilenameShort(QString(), ".fpl"), false /* confirm overwrite */, OptionData::instance().getFlags2() & opts2::PROPOSE_FILENAME); if(!routeFile.isEmpty()) { - if(exportFlighplanAsIvap(exportData, routeFile)) + if(exportFlighplanAsIvap(exportData, routeFile, type)) { - mainWindow->setStatusMessage(tr("Flight plan saved for IvAp/X-IvAp.")); + mainWindow->setStatusMessage(tr("Flight plan saved for %1.").arg(typeStr)); return true; } } @@ -702,6 +714,7 @@ bool RouteExport::routeExportIvap() RouteExportData RouteExport::createRouteExportData(re::RouteExportType routeExportType) { RouteExportData exportData; + const Route& route = NavApp::getRouteConst(); exportData.setRoute(RouteString::createStringForRoute(route, 0.f, rs::SID_STAR)); exportData.setDeparture(route.getFlightplan().getDepartureIdent()); @@ -710,6 +723,12 @@ RouteExportData RouteExport::createRouteExportData(re::RouteExportType routeExpo exportData.setDepartureTimeActual(QDateTime::currentDateTimeUtc().time()); exportData.setCruiseAltitude(atools::roundToInt(route.getCruisingAltitudeFeet())); + QStringList alternates = route.getAlternateIdents(); + if(alternates.size() > 0) + exportData.setAlternate(alternates.at(0)); + if(alternates.size() > 1) + exportData.setAlternate2(alternates.at(1)); + atools::fs::pln::FlightplanType flightplanType = route.getFlightplan().getFlightplanType(); switch(routeExportType) { @@ -724,6 +743,7 @@ RouteExportData RouteExport::createRouteExportData(re::RouteExportType routeExpo break; case re::IVAP: + case re::XIVAP: // [FLIGHTPLAN] // FLIGHTTYPE=N @@ -1130,7 +1150,8 @@ bool RouteExport::exportFlighplanAsVfp(const RouteExportData& exportData, const } } -bool RouteExport::exportFlighplanAsIvap(const RouteExportData& exportData, const QString& filename) +bool RouteExport::exportFlighplanAsIvap(const RouteExportData& exportData, const QString& filename, + re::RouteExportType type) { QFile file(filename); if(file.open(QFile::WriteOnly | QIODevice::Text)) @@ -1164,31 +1185,43 @@ bool RouteExport::exportFlighplanAsIvap(const RouteExportData& exportData, const // RULES=I QTextStream stream(&file); stream << "[FLIGHTPLAN]" << endl; - stream << "CALLSIGN=" << exportData.getCallsign() << endl; - stream << "PIC=" << exportData.getPilotInCommand() << endl; - stream << "LIVERY=" << exportData.getLivery() << endl; - stream << "AIRLINE=" << exportData.getAirline() << endl; - stream << "SPEEDTYPE=N" << endl; - stream << "POB=" << exportData.getPassengers() << endl; - stream << "ENDURANCE=" << minToHourMinStr(exportData.getEnduranceMinutes()) << endl; - stream << "OTHER=" << exportData.getRemarks() << endl; - stream << "ALT2ICAO=" << exportData.getAlternate2() << endl; - stream << "ALTICAO=" << exportData.getAlternate() << endl; - stream << "EET=" << minToHourMinStr(exportData.getEnrouteMinutes()) << endl; - stream << "DESTICAO=" << exportData.getDestination() << endl; - stream << "ROUTE=" << exportData.getRoute() << endl; - stream << "LEVEL=" << exportData.getCruiseAltitude() / 100 << endl; - stream << "LEVELTYPE=F" << endl; - stream << "SPEED=" << exportData.getSpeed() << endl; - stream << "DEPTIME=" << exportData.getDepartureTime().toString("HHmm") << endl; - stream << "DEPICAO=" << exportData.getDeparture() << endl; - stream << "TRANSPONDER=" << exportData.getTransponder() << endl; - stream << "EQUIPMENT=" << exportData.getEquipment() << endl; - stream << "WAKECAT=" << exportData.getWakeCategory() << endl; - stream << "ACTYPE=" << exportData.getAircraftType() << endl; - stream << "NUMBER=1" << endl; - stream << "FLIGHTTYPE=" << exportData.getFlightType() << endl; - stream << "RULES=" << exportData.getFlightRules() << endl; + + if(type == re::XIVAP) + { + stream << endl; + writeIvapLine(stream, "CALLSIGN", exportData.getCallsign(), type); + writeIvapLine(stream, "LIVERY", exportData.getLivery(), type); + writeIvapLine(stream, "AIRLINE", exportData.getAirline(), type); + writeIvapLine(stream, "PIC", exportData.getPilotInCommand(), type); + writeIvapLine(stream, "ALT2ICAO", exportData.getAlternate2(), type); + writeIvapLine(stream, "FMCROUTE", QString(), type); + } + else + { + writeIvapLine(stream, "ID", exportData.getCallsign(), type); + writeIvapLine(stream, "ALTICAO2", exportData.getAlternate2(), type); + } + + writeIvapLine(stream, "SPEEDTYPE", "N", type); + writeIvapLine(stream, "POB", exportData.getPassengers(), type); + writeIvapLine(stream, "ENDURANCE", minToHourMinStr(exportData.getEnduranceMinutes()), type); + writeIvapLine(stream, "OTHER", exportData.getRemarks(), type); + writeIvapLine(stream, "ALTICAO", exportData.getAlternate(), type); + writeIvapLine(stream, "EET", minToHourMinStr(exportData.getEnrouteMinutes()), type); + writeIvapLine(stream, "DESTICAO", exportData.getDestination(), type); + writeIvapLine(stream, "ROUTE", exportData.getRoute(), type); + writeIvapLine(stream, "LEVEL", exportData.getCruiseAltitude() / 100, type); + writeIvapLine(stream, "LEVELTYPE", "F", type); + writeIvapLine(stream, "SPEED", exportData.getSpeed(), type); + writeIvapLine(stream, "DEPTIME", exportData.getDepartureTime().toString("HHmm"), type); + writeIvapLine(stream, "DEPICAO", exportData.getDeparture(), type); + writeIvapLine(stream, "TRANSPONDER", exportData.getTransponder(), type); + writeIvapLine(stream, "EQUIPMENT", exportData.getEquipment(), type); + writeIvapLine(stream, "WAKECAT", exportData.getWakeCategory(), type); + writeIvapLine(stream, "ACTYPE", exportData.getAircraftType(), type); + writeIvapLine(stream, "NUMBER", "1", type); + writeIvapLine(stream, "FLIGHTTYPE", exportData.getFlightType(), type); + writeIvapLine(stream, "RULES", exportData.getFlightRules(), type); file.close(); return true; @@ -1447,3 +1480,17 @@ QString RouteExport::minToHourMinStr(int minutes) int enrouteHours = minutes / 60; return QString("%1%2").arg(enrouteHours, 2, 10, QChar('0')).arg(minutes - enrouteHours * 60, 2, 10, QChar('0')); } + +void RouteExport::writeIvapLine(QTextStream& stream, const QString& key, const QString& value, re::RouteExportType type) +{ + stream << key << "=" << value << endl; + if(type == re::XIVAP) + stream << endl; +} + +void RouteExport::writeIvapLine(QTextStream& stream, const QString& key, int value, re::RouteExportType type) +{ + stream << key << "=" << value << endl; + if(type == re::XIVAP) + stream << endl; +} diff --git a/src/route/routeexport.h b/src/route/routeexport.h index fbf9f8ae6..663199184 100644 --- a/src/route/routeexport.h +++ b/src/route/routeexport.h @@ -42,6 +42,7 @@ class Dialog; class MainWindow; class Route; class RouteExportData; +class QTextStream; /* * Covers all flight plan export and export related functions including validation and warning dialogs. @@ -104,6 +105,7 @@ class RouteExport : /* IVAP or X-IVAP for IVAO */ bool routeExportIvap(); + bool routeExportXIvap(); /* FeelThere or Wilco aircraft */ bool routeExportFeelthereFpl(); @@ -164,6 +166,8 @@ class RouteExport : bool exportFlighplan(const QString& filename, std::function exportFunc); + bool routeExportIvapInternal(re::RouteExportType type); + /* Show online network dialog which allows the user to enter needed data */ bool routeExportDialog(RouteExportData& exportData, re::RouteExportType flightplanType); @@ -174,9 +178,12 @@ class RouteExport : bool exportFlighplanAsVfp(const RouteExportData& exportData, const QString& filename); /* Export IVAP or X-IVAP */ - bool exportFlighplanAsIvap(const RouteExportData& exportData, const QString& filename); + bool exportFlighplanAsIvap(const RouteExportData& exportData, const QString& filename, re::RouteExportType type); QString minToHourMinStr(int minutes); + void writeIvapLine(QTextStream& stream, const QString& key, const QString& value, re::RouteExportType type); + void writeIvapLine(QTextStream& stream, const QString& key, int value, re::RouteExportType type); + MainWindow *mainWindow; atools::gui::Dialog *dialog; atools::fs::pln::FlightplanIO *flightplanIO; diff --git a/src/route/routeexportdialog.cpp b/src/route/routeexportdialog.cpp index 68b82cb64..8ba72e5d5 100644 --- a/src/route/routeexportdialog.cpp +++ b/src/route/routeexportdialog.cpp @@ -31,7 +31,6 @@ RouteExportDialog::RouteExportDialog(QWidget *parent, re::RouteExportType routeT { setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); setWindowModality(Qt::ApplicationModal); - ui->setupUi(this); widgets.append(ui->checkBoxHeavy); @@ -60,7 +59,6 @@ RouteExportDialog::RouteExportDialog(QWidget *parent, re::RouteExportType routeT break; case re::VFP: - ui->lineEditFlightType->setVisible(false); ui->labelFlightType->setVisible(false); ui->lineEditAircraftType->setVisible(false); @@ -104,17 +102,45 @@ RouteExportDialog::RouteExportDialog(QWidget *parent, re::RouteExportType routeT break; - case re::IVAP: + case re::XIVAP: + ui->checkBoxHeavy->setVisible(false); + + ui->lineEditVoiceType->setVisible(false); + ui->labelVoiceType->setVisible(false); + + ui->timeEditDepartureActual->setVisible(false); + ui->labelTimeDepartureActual->setVisible(false); + ui->lineEditEquipmentPrefix->setVisible(false); + ui->lineEditEquipmentSuffix->setVisible(false); + ui->labelEquipmentPrefixSuffix->setVisible(false); + + ui->lineEditLivery->setVisible(false); + ui->labelLivery->setVisible(false); + break; + + case re::IVAP: ui->checkBoxHeavy->setVisible(false); + ui->lineEditVoiceType->setVisible(false); ui->labelVoiceType->setVisible(false); + ui->timeEditDepartureActual->setVisible(false); ui->labelTimeDepartureActual->setVisible(false); + ui->lineEditEquipmentPrefix->setVisible(false); ui->lineEditEquipmentSuffix->setVisible(false); ui->labelEquipmentPrefixSuffix->setVisible(false); + ui->lineEditLivery->setVisible(false); + ui->labelLivery->setVisible(false); + + ui->lineEditPilotInCommand->setVisible(false); + ui->labelPilotInCommand->setVisible(false); + + ui->lineEditAirline->setVisible(false); + ui->labelAirline->setVisible(false); + // [FLIGHTPLAN] // CALLSIGN=VPI333 // PIC=NAME @@ -146,19 +172,18 @@ RouteExportDialog::RouteExportDialog(QWidget *parent, re::RouteExportType routeT break; } + setWindowTitle(tr("%1 - Export for %2").arg(QApplication::applicationName()).arg(getRouteTypeAsDisplayString(type))); + connect(ui->buttonBox, &QDialogButtonBox::clicked, this, &RouteExportDialog::buttonBoxClicked); // Saves original texts and restores them on deletion units = new UnitStringTool(); - units->init({ - ui->spinBoxTrueAirspeed, - ui->spinBoxCruiseAltitude, - }); + units->init({ui->spinBoxTrueAirspeed, ui->spinBoxCruiseAltitude}); } RouteExportDialog::~RouteExportDialog() { - atools::gui::WidgetState(lnm::FLIGHTPLAN_ONLINE_EXPORT + routeTypeAsString(type)).save(this); + atools::gui::WidgetState(lnm::FLIGHTPLAN_ONLINE_EXPORT + getRouteTypeAsString(type)).save(this); delete units; delete ui; @@ -263,7 +288,7 @@ void RouteExportDialog::dialogToData(RouteExportData& data) data.setRemarks(ui->lineEditRemarks->text()); } -QString RouteExportDialog::routeTypeAsString(re::RouteExportType routeType) +QString RouteExportDialog::getRouteTypeAsString(re::RouteExportType routeType) { switch(routeType) { @@ -276,6 +301,29 @@ QString RouteExportDialog::routeTypeAsString(re::RouteExportType routeType) case re::IVAP: return "Ivap"; + case re::XIVAP: + return "XIvap"; + + } + return QString(); +} + +QString RouteExportDialog::getRouteTypeAsDisplayString(re::RouteExportType routeType) +{ + switch(routeType) + { + case re::UNKNOWN: + break; + + case re::VFP: + return tr("VPilot"); + + case re::IVAP: + return tr("IvAp"); + + case re::XIVAP: + return tr("X-IvAp"); + } return QString(); } @@ -316,14 +364,14 @@ void RouteExportDialog::clearDialog() void RouteExportDialog::restoreState() { - atools::gui::WidgetState ws(lnm::FLIGHTPLAN_ONLINE_EXPORT + routeTypeAsString(type)); + atools::gui::WidgetState ws(lnm::FLIGHTPLAN_ONLINE_EXPORT + getRouteTypeAsString(type)); ws.restore(this); ws.restore(widgets); } void RouteExportDialog::saveState() { - atools::gui::WidgetState ws(lnm::FLIGHTPLAN_ONLINE_EXPORT + routeTypeAsString(type)); + atools::gui::WidgetState ws(lnm::FLIGHTPLAN_ONLINE_EXPORT + getRouteTypeAsString(type)); ws.save(this); ws.save(widgets); } diff --git a/src/route/routeexportdialog.h b/src/route/routeexportdialog.h index 70b04a05b..1ea214bad 100644 --- a/src/route/routeexportdialog.h +++ b/src/route/routeexportdialog.h @@ -29,7 +29,8 @@ enum RouteExportType { UNKNOWN, VFP, /* VATSIM VFP format - vPilot */ - IVAP /* IVAO IVAP or X-IVAP */ + IVAP, /* IVAO IVAP */ + XIVAP /* IVAO X-IVAP */ }; } @@ -56,11 +57,13 @@ class RouteExportDialog : RouteExportData getExportData() const; void setExportData(const RouteExportData& value); + static QString getRouteTypeAsDisplayString(re::RouteExportType routeType); + static QString getRouteTypeAsString(re::RouteExportType routeType); + private: void buttonBoxClicked(QAbstractButton *button); void dataToDialog(const RouteExportData& data); void dialogToData(RouteExportData& data); - QString routeTypeAsString(re::RouteExportType routeType); void clearDialog(); Ui::RouteExportDialog *ui;