diff --git a/src/blackgui/components/flightplancomponent.cpp b/src/blackgui/components/flightplancomponent.cpp index 9769d26c2..d911d0307 100644 --- a/src/blackgui/components/flightplancomponent.cpp +++ b/src/blackgui/components/flightplancomponent.cpp @@ -556,7 +556,7 @@ namespace BlackGui void CFlightPlanComponent::buildRemarksString() { QString v = ui->cb_VoiceCapabilities->currentText().toUpper(); - QString rem = CFlightPlanRemarks::textToVoiceCapabilities(v); + QString rem = CFlightPlanRemarks::textToVoiceCapabilitiesRemarks(v); v = ui->le_AirlineOperator->text().trimmed(); if (!v.isEmpty()) rem.append("OPR/").append(v).append(" "); @@ -830,7 +830,7 @@ namespace BlackGui else { ui->cb_VoiceCapabilities->setCurrentText(text); - const QString r = CFlightPlanRemarks::replaceVoiceCapabilities(CFlightPlanRemarks::textToVoiceCapabilities(text), ui->pte_Remarks->toPlainText()); + const QString r = CFlightPlanRemarks::replaceVoiceCapabilities(CFlightPlanRemarks::textToVoiceCapabilitiesRemarks(text), ui->pte_Remarks->toPlainText()); ui->pte_Remarks->setPlainText(r); } } diff --git a/src/blackmisc/aviation/flightplan.cpp b/src/blackmisc/aviation/flightplan.cpp index 8c15b5b96..240511ff5 100644 --- a/src/blackmisc/aviation/flightplan.cpp +++ b/src/blackmisc/aviation/flightplan.cpp @@ -21,6 +21,7 @@ #include #include #include +#include using namespace BlackMisc::Network; using namespace BlackMisc::PhysicalQuantities; @@ -43,6 +44,11 @@ namespace BlackMisc if (parse) { this->parseFlightPlanRemarks(); } } + void CFlightPlanRemarks::setVoiceCapabilities(const CVoiceCapabilities &capabilities) + { + m_voiceCapabilities = capabilities; + } + bool CFlightPlanRemarks::hasAnyParsedRemarks() const { if (!m_isParsed) { return false; } @@ -67,24 +73,22 @@ namespace BlackMisc return s.simplified().trimmed(); } - QString CFlightPlanRemarks::textToVoiceCapabilities(const QString &text) + QString CFlightPlanRemarks::textToVoiceCapabilitiesRemarks(const QString &text) { - if (text.contains("TEXT", Qt::CaseInsensitive)) { return QStringLiteral("/T/"); } - if (text.contains("RECEIVE", Qt::CaseInsensitive)) { return QStringLiteral("/R/"); } - if (text.contains("VOICE", Qt::CaseInsensitive)) { return QStringLiteral("/V/"); } - return QStringLiteral(""); + const CVoiceCapabilities vc = CVoiceCapabilities::fromText(text); + return vc.toFlightPlanRemarks(); } - QString CFlightPlanRemarks::replaceVoiceCapabilities(const QString &newCaps, const QString &oldRemarks) + QString CFlightPlanRemarks::replaceVoiceCapabilities(const QString &newCapRemarks, const QString &oldRemarks) { - if (newCaps.isEmpty()) { return oldRemarks; } - if (oldRemarks.isEmpty()) { return newCaps; } + if (newCapRemarks.isEmpty()) { return oldRemarks; } + if (oldRemarks.isEmpty()) { return newCapRemarks; } QString r(oldRemarks); - if (r.contains("/V/", Qt::CaseInsensitive)) { r.replace("/V/", newCaps, Qt::CaseInsensitive); return r; } - if (r.contains("/R/", Qt::CaseInsensitive)) { r.replace("/R/", newCaps, Qt::CaseInsensitive); return r; } - if (r.contains("/T/", Qt::CaseInsensitive)) { r.replace("/T/", newCaps, Qt::CaseInsensitive); return r; } - return newCaps % QStringLiteral(" ") % r; + if (r.contains("/V/", Qt::CaseInsensitive)) { r.replace("/V/", newCapRemarks, Qt::CaseInsensitive); return r; } + if (r.contains("/R/", Qt::CaseInsensitive)) { r.replace("/R/", newCapRemarks, Qt::CaseInsensitive); return r; } + if (r.contains("/T/", Qt::CaseInsensitive)) { r.replace("/T/", newCapRemarks, Qt::CaseInsensitive); return r; } + return newCapRemarks % QStringLiteral(" ") % r; } QString CFlightPlanRemarks::cleanRemarks(const QString &remarksIn) @@ -194,6 +198,12 @@ namespace BlackMisc m_remarks = CFlightPlanRemarks(remarks, true); } + void CFlightPlan::setVoiceCapabilities(const QString &capabilities) + { + const CVoiceCapabilities vc = CVoiceCapabilities::fromText(capabilities); + m_remarks.setVoiceCapabilities(vc); + } + CFlightPlan::FlightRules CFlightPlan::getFlightRulesAsVFRorIFR() const { switch (this->getFlightRules()) @@ -208,6 +218,23 @@ namespace BlackMisc return UNKNOWN; } + void CFlightPlan::setPrefix(const QString &prefix) + { + m_prefix = prefix; + m_prefix.remove('/'); + } + + void CFlightPlan::setHeavy() + { + this->setPrefix("H"); + } + + void CFlightPlan::setEquipmentSuffix(const QString &suffix) + { + m_equipmentSuffix = suffix; + m_equipmentSuffix.remove('/'); + } + QString CFlightPlan::getCombinedPrefixIcaoSuffix() const { return CFlightPlan::concatPrefixIcaoSuffix(m_prefix, m_aircraftIcao.getDesignator(), m_equipmentSuffix); @@ -272,7 +299,64 @@ namespace BlackMisc CFlightPlan CFlightPlan::fromVPilotFormat(const QString &vPilotData) { if (vPilotData.isEmpty()) { return CFlightPlan(); } - return CFlightPlan(); + QDomDocument doc; + doc.setContent(vPilotData); + const QDomElement fpDom = doc.firstChildElement(); + const QString type = fpDom.attribute("FlightType"); + + CFlightPlan fp; + fp.setFlightRule(CFlightPlan::stringToFlightRules(type)); + + const int airspeedKts = fpDom.attribute("CruiseSpeed").toInt(); + const CSpeed airspeed(airspeedKts, CSpeedUnit::kts()); + fp.setCruiseTrueAirspeed(airspeed); + + fp.setOriginAirportIcao(fpDom.attribute("DepartureAirport")); + fp.setDestinationAirportIcao(fpDom.attribute("DestinationAirport")); + fp.setAlternateAirportIcao(fpDom.attribute("AlternateAirport")); + fp.setRemarks(fpDom.attribute("Remarks")); + fp.setRoute(fpDom.attribute("Route")); + + const QString voice = fpDom.attribute("VoiceType"); + fp.setVoiceCapabilities(voice); + + const QString prefix = fpDom.attribute("EquipmentPrefix"); + if (prefix.isEmpty()) + { + const bool heavy = stringToBool(fpDom.attribute("IsHeavy")); + if (heavy) { fp.setHeavy(); } + } + else + { + fp.setPrefix(prefix); + } + fp.setEquipmentSuffix(fpDom.attribute("EquipmentSuffix")); + + const int fuelMins = fpDom.attribute("FuelMinutes").toInt() + 60 * fpDom.attribute("FuelHours").toInt(); + const CTime fuelTime(fuelMins, CTimeUnit::min()); + + const int enrouteMins = fpDom.attribute("EnrouteMinutes").toInt() + 60 * fpDom.attribute("EnrouteHours").toInt(); + const CTime enrouteTime(enrouteMins, CTimeUnit::min()); + + const QString altStr = fpDom.attribute("CruiseAltitude"); + CAltitude alt(altStr.length() < 4 ? "FL" + altStr : altStr + "ft"); + alt.toFlightLevel(); + + fp.setCruiseAltitude(alt); + fp.setFuelTime(fuelTime); + fp.setEnrouteTime(enrouteTime); + + const QString departureTime = fpDom.attribute("DepartureTime"); + if (departureTime.length() == 4) + { + CTime depTime; + if (depTime.parseFromString_hhmm(departureTime)) + { + fp.setTakeoffTimePlanned(depTime.toQDateTime()); + } + } + + return fp; } CFlightPlan CFlightPlan::fromSB4Format(const QString &sbData) @@ -281,7 +365,7 @@ namespace BlackMisc CFlightPlan fp; const QMap values = parseIniValues(sbData); const QString altStr = values.value("Altitude"); - const CAltitude alt(altStr.length() < 4 ? "FL" + altStr : altStr); + const CAltitude alt(altStr.length() < 4 ? "FL" + altStr : altStr + "ft"); const QString type = values.value("Type"); // IFR/VFR fp.setFlightRule(type == "0" ? IFR : VFR); @@ -309,7 +393,7 @@ namespace BlackMisc fp.setCruiseTrueAirspeed(airspeed); const bool heavy = stringToBool(values.value("Heavy")); - if (heavy) { fp.setPrefix("H"); } + if (heavy) { fp.setHeavy(); } return fp; } diff --git a/src/blackmisc/aviation/flightplan.h b/src/blackmisc/aviation/flightplan.h index 85153caf4..7771084c8 100644 --- a/src/blackmisc/aviation/flightplan.h +++ b/src/blackmisc/aviation/flightplan.h @@ -78,6 +78,12 @@ namespace BlackMisc //! Voice capabilities const Network::CVoiceCapabilities &getVoiceCapabilities() const { return m_voiceCapabilities; } + //! Set voice capabilities + void setVoiceCapabilitiesByText(const QString &text); + + //! Set voice capabilities + void setVoiceCapabilities(const Network::CVoiceCapabilities &capabilities); + //! Any remarks available? bool hasAnyParsedRemarks() const; @@ -101,10 +107,10 @@ namespace BlackMisc QString convertToQString(bool i18n = false) const; //! Turn text into voice capabilities for remarks - static QString textToVoiceCapabilities(const QString &text); + static QString textToVoiceCapabilitiesRemarks(const QString &text); //! Replace the voice capabilities remarks part - static QString replaceVoiceCapabilities(const QString &newCaps, const QString &oldRemarks); + static QString replaceVoiceCapabilities(const QString &newCapRemarks, const QString &oldRemarks); //! Clean up remarks string static QString cleanRemarks(const QString &remarksIn); @@ -239,6 +245,9 @@ namespace BlackMisc //! Set remarks string (max 100 characters) void setRemarks(const QString &remarks); + //! Set voice capabilities + void setVoiceCapabilities(const QString &capabilities); + //! When last sent void setWhenLastSentOrLoaded(const QDateTime &dateTime) { this->setUtcTimestamp(dateTime); } @@ -318,13 +327,16 @@ namespace BlackMisc const QString &getPrefix() const { return m_prefix; } //! Set ICAO aircraft equipment prefix H/B737/F "H" - void setPrefix(const QString &prefix) { m_prefix = prefix; } + void setPrefix(const QString &prefix); + + //! Mark as heavy + void setHeavy(); //! Get ICAO aircraft equipment suffix H/B737/F "F" const QString &getEquipmentSuffix() const { return m_equipmentSuffix; } //! Set ICAO aircraft equipment suffix H/B737/F "F" - void setEquipmentSuffix(const QString &suffix) { m_equipmentSuffix = suffix; } + void setEquipmentSuffix(const QString &suffix); //! Get aircraft ICAO H/B737/F "B737" const CAircraftIcaoCode &getAircraftIcao() const { return m_aircraftIcao; } diff --git a/src/blackmisc/network/voicecapabilites.cpp b/src/blackmisc/network/voicecapabilites.cpp index 267062365..386910919 100644 --- a/src/blackmisc/network/voicecapabilites.cpp +++ b/src/blackmisc/network/voicecapabilites.cpp @@ -27,6 +27,25 @@ namespace BlackMisc this->setFromFlightPlanRemarks(flightPlanRemarks); } + const QString &CVoiceCapabilities::toFlightPlanRemarks() const + { + static const QString v("/R/"); + static const QString t("/T/"); + static const QString r("/R/"); + static const QString u(""); + + switch (m_voiceCapabilities) + { + case Voice: return v; + case TextOnly: return t; + case VoiceReceivingOnly: return r; + case Unknown: return u; + default: break; + } + Q_ASSERT_X(false, Q_FUNC_INFO, "Illegal mode"); + return u; + } + QString CVoiceCapabilities::convertToQString(bool i18n) const { Q_UNUSED(i18n); @@ -100,6 +119,16 @@ namespace BlackMisc return CVoiceCapabilities(remarks); } + CVoiceCapabilities CVoiceCapabilities::fromText(const QString &text) + { + if (text.startsWith("/")) { return CVoiceCapabilities::fromText(text); } + if (text.contains("TEXT", Qt::CaseInsensitive)) { return CVoiceCapabilities(TextOnly); } + if (text.contains("ONLY", Qt::CaseInsensitive)) { return CVoiceCapabilities(TextOnly); } + if (text.contains("RECEIVE", Qt::CaseInsensitive)) { return CVoiceCapabilities(VoiceReceivingOnly); } + if (text.contains("VOICE", Qt::CaseInsensitive)) { return CVoiceCapabilities(Voice); } + return CVoiceCapabilities(Unknown); + } + const QList &CVoiceCapabilities::allCapabilities() { static const QList all({fromVoiceCapabilities(Unknown), fromVoiceCapabilities(Voice), fromVoiceCapabilities(VoiceReceivingOnly), fromVoiceCapabilities(TextOnly)}); diff --git a/src/blackmisc/network/voicecapabilities.h b/src/blackmisc/network/voicecapabilities.h index f2af068d8..5f76d9748 100644 --- a/src/blackmisc/network/voicecapabilities.h +++ b/src/blackmisc/network/voicecapabilities.h @@ -50,12 +50,18 @@ namespace BlackMisc //! Is capability known bool isUnknown() const { return m_voiceCapabilities == Unknown; } + //! To flight plan remarks + const QString &toFlightPlanRemarks() const; + //! From enum static const CVoiceCapabilities &fromVoiceCapabilities(VoiceCapabilities capabilities); //! From flight plan remarks static CVoiceCapabilities fromFlightPlanRemarks(const QString &remarks); + //! From text like "text only" + static CVoiceCapabilities fromText(const QString &text); + //! All capabilities as list static const QList &allCapabilities();