diff --git a/src/blackmisc/aviation/flightplan.cpp b/src/blackmisc/aviation/flightplan.cpp index d372b2b0e..8c15b5b96 100644 --- a/src/blackmisc/aviation/flightplan.cpp +++ b/src/blackmisc/aviation/flightplan.cpp @@ -10,12 +10,20 @@ #include "flightplan.h" #include "airlineicaocode.h" #include "flightplan.h" +#include "altitude.h" +#include "blackmisc/pq/time.h" +#include "blackmisc/pq/speed.h" #include "blackmisc/iconlist.h" -#include "blackmisc/icons.h" +#include "blackmisc/fileutils.h" +#include "blackmisc/stringutils.h" + +#include +#include #include #include using namespace BlackMisc::Network; +using namespace BlackMisc::PhysicalQuantities; namespace BlackMisc { @@ -113,7 +121,6 @@ namespace BlackMisc } } - QString CFlightPlanRemarks::cut(const QString &remarks, const QString &marker) { const int maxIndex = remarks.size() - 1; @@ -137,6 +144,12 @@ namespace BlackMisc return cut; } + const CLogCategoryList &CFlightPlan::getLogCategories() + { + static const CLogCategoryList cats { CLogCategory::flightPlan() }; + return cats; + } + CFlightPlan::CFlightPlan() { } CFlightPlan::CFlightPlan(const CCallsign &callsign, const QString &equipmentIcao, const CAirportIcaoCode &originAirportIcao, const CAirportIcaoCode &destinationAirportIcao, @@ -256,6 +269,116 @@ namespace BlackMisc return s; } + CFlightPlan CFlightPlan::fromVPilotFormat(const QString &vPilotData) + { + if (vPilotData.isEmpty()) { return CFlightPlan(); } + return CFlightPlan(); + } + + CFlightPlan CFlightPlan::fromSB4Format(const QString &sbData) + { + if (sbData.isEmpty()) { return CFlightPlan(); } + CFlightPlan fp; + const QMap values = parseIniValues(sbData); + const QString altStr = values.value("Altitude"); + const CAltitude alt(altStr.length() < 4 ? "FL" + altStr : altStr); + + const QString type = values.value("Type"); // IFR/VFR + fp.setFlightRule(type == "0" ? IFR : VFR); + + const int fuelMins = values.value("FuelMinutes").toInt() + 60 * values.value("FuelHours").toInt(); + const CTime fuelTime(fuelMins, CTimeUnit::min()); + + const int enrouteMins = values.value("FlightMinutes").toInt() + 60 * values.value("FlightHours").toInt(); + const CTime enrouteTime(enrouteMins, CTimeUnit::min()); + + fp.setOriginAirportIcao(values.value("Departure")); + fp.setDestinationAirportIcao(values.value("Arrival")); + fp.setAlternateAirportIcao(values.value("Alternate")); + fp.setRemarks(values.value("Remarks")); + fp.setRoute(values.value("Route")); + + fp.setCruiseAltitude(alt); + fp.setFuelTime(fuelTime); + fp.setEnrouteTime(enrouteTime); + + fp.setTakeoffTimePlanned(QDateTime::currentDateTimeUtc()); + + int airspeedKts = values.value("Airspeed").toInt(); + const CSpeed airspeed(airspeedKts, CSpeedUnit::kts()); + fp.setCruiseTrueAirspeed(airspeed); + + const bool heavy = stringToBool(values.value("Heavy")); + if (heavy) { fp.setPrefix("H"); } + + return fp; + } + + CFlightPlan CFlightPlan::fromMultipleFormats(const QString &data) + { + if (data.isEmpty()) { return CFlightPlan(); } + if (data.contains("[SBFlightPlan]", Qt::CaseInsensitive)) { return CFlightPlan::fromSB4Format(data); } + if (data.contains("push_back(CStatusMessage(getLogCategories()).validationError("No file name")); } + return CFlightPlan(); + } + else + { + QFile f(fileName); + if (!f.exists()) + { + if (msgs) { msgs->push_back(CStatusMessage(getLogCategories()).validationError("File '%1' does not exist") << fileName); } + return CFlightPlan(); + } + } + + const QString data = CFileUtils::readFileToString(fileName); + if (data.isEmpty()) + { + if (msgs) { msgs->push_back(CStatusMessage(getLogCategories()).validationError("File '%1' does not contain data") << fileName); } + return CFlightPlan(); + } + + if (fileName.endsWith(".sfp", Qt::CaseInsensitive)) { return CFlightPlan::fromSB4Format(data); } + if (fileName.endsWith(".vfp", Qt::CaseInsensitive)) { return CFlightPlan::fromVPilotFormat(data); } + if (fileName.endsWith(".json", Qt::CaseInsensitive)) { return CFlightPlan::fromJson(data); } + + return CFlightPlan::fromMultipleFormats(data); + } + catch (const CJsonException &ex) + { + if (msgs) + { + msgs->push_back(ex.toStatusMessage(getLogCategories(), QString("Parsing flight plan from '%1' failed.").arg(fileName))); + } + } + return CFlightPlan(); + } + const QString CFlightPlan::flightRuleToString(CFlightPlan::FlightRules rule) { switch (rule) diff --git a/src/blackmisc/aviation/flightplan.h b/src/blackmisc/aviation/flightplan.h index 5902e0f5e..85153caf4 100644 --- a/src/blackmisc/aviation/flightplan.h +++ b/src/blackmisc/aviation/flightplan.h @@ -22,6 +22,8 @@ #include "blackmisc/pq/speed.h" #include "blackmisc/pq/time.h" #include "blackmisc/pq/units.h" +#include "blackmisc/statusmessagelist.h" +#include "blackmisc/logcategorylist.h" #include "blackmisc/timestampbased.h" #include "blackmisc/valueobject.h" #include "blackmisc/metaclass.h" @@ -139,6 +141,9 @@ namespace BlackMisc public ITimestampBased { public: + //! The log. catgeories + static const CLogCategoryList &getLogCategories(); + //! Flight rules (VFR or IFR) enum FlightRules { @@ -162,7 +167,7 @@ namespace BlackMisc //! \fixme max.length of complete flight plan is 768 characters, this here is an assumption and should be part of the underlying network layers // https://forums.vatsim.net/viewtopic.php?f=6&t=63416 static constexpr int MaxRemarksLength = 256; //!< Max.remarks length - static constexpr int MaxRouteLength = 256; //!< Max.route length + static constexpr int MaxRouteLength = 256; //!< Max.route length //! Default constructor CFlightPlan(); @@ -345,6 +350,21 @@ namespace BlackMisc //! \copydoc BlackMisc::Mixin::String::toQString() QString convertToQString(bool i18n = false) const; + //! From vPilot data + static CFlightPlan fromVPilotFormat(const QString &vPilotData); + + //! From SB4 data + static CFlightPlan fromSB4Format(const QString &sbData); + + //! From multiple formats + static CFlightPlan fromMultipleFormats(const QString &data); + + //! From multiple formats + static CFlightPlan fromMultipleFormatsNoThrow(const QString &data); + + //! Load from multiple formats + static CFlightPlan loadFromMultipleFormats(const QString &fileName, CStatusMessageList *msgs = nullptr); + //! Rules to string static const QString flightRuleToString(FlightRules rule);