diff --git a/samples/blackmiscquantities/samplesphysicalquantities.cpp b/samples/blackmiscquantities/samplesphysicalquantities.cpp index 25078f6e5..f3e12a557 100644 --- a/samples/blackmiscquantities/samplesphysicalquantities.cpp +++ b/samples/blackmiscquantities/samplesphysicalquantities.cpp @@ -15,9 +15,11 @@ namespace BlackMiscTest */ int CSamplesPhysicalQuantities::samples() { - QVariant parsedPq = CPqString::parseToVariant("100 km/h"); - parsedPq = CPqString::parseToVariant("-33ft"); - parsedPq = CPqString::parseToVariant("666"); + CSpeed parsedPq1 = CPqString::parseToVariant("100 km/h").value(); + CLength parsedPq2 = CPqString::parseToVariant("-33ft").value(); + QVariant parsedPq3 = CPqString::parseToVariant("666"); + qDebug() << "parsed" << parsedPq1 << parsedPq2 << parsedPq3; + CSpeed speedParsed = CPqString::parse("111.33ft/s"); CFrequency frequencyParsed = CPqString::parse("122.8MHz"); qDebug() << "parsed" << speedParsed << speedParsed.valueRoundedWithUnit(2, true) << frequencyParsed << frequencyParsed.valueRoundedWithUnit(2, true); diff --git a/samples/cli_client/client.cpp b/samples/cli_client/client.cpp index 5cbe95413..fd07bef12 100644 --- a/samples/cli_client/client.cpp +++ b/samples/cli_client/client.cpp @@ -252,26 +252,29 @@ void Client::sendFlightPlanCmd(QTextStream &args) QString flightRulesString; QString route; args >> equipmentIcao >> originAirportIcao >> destinationAirportIcao >> alternateAirportIcao >> takeoffTimePlanned >> takeoffTimeActual - >> enrouteTime >> fuelTime >> cruiseAltitude >> cruiseTrueAirspeed >> flightRulesString >> route; + >> enrouteTime >> fuelTime >> cruiseAltitude >> cruiseTrueAirspeed >> flightRulesString >> route; BlackMisc::Aviation::CFlightPlan::FlightRules flightRules; if (flightRulesString == "IFR") { flightRules = BlackMisc::Aviation::CFlightPlan::IFR; } else if (flightRulesString == "SVFR") { flightRules = BlackMisc::Aviation::CFlightPlan::SVFR; } else { flightRules = BlackMisc::Aviation::CFlightPlan::VFR; } - BlackMisc::Aviation::CFlightPlan fp(equipmentIcao, originAirportIcao, destinationAirportIcao, alternateAirportIcao, - QDateTime::fromString(takeoffTimePlanned, "hhmm"), QDateTime::fromString(takeoffTimeActual, "hhmm"), - BlackMisc::PhysicalQuantities::CTime(enrouteTime, BlackMisc::PhysicalQuantities::CTimeUnit::hrmin()), - BlackMisc::PhysicalQuantities::CTime(fuelTime, BlackMisc::PhysicalQuantities::CTimeUnit::hrmin()), - BlackMisc::Aviation::CAltitude(cruiseAltitude, BlackMisc::Aviation::CAltitude::MeanSeaLevel, BlackMisc::PhysicalQuantities::CLengthUnit::ft()), - BlackMisc::PhysicalQuantities::CSpeed(cruiseTrueAirspeed, BlackMisc::PhysicalQuantities::CSpeedUnit::kts()), - flightRules, route, args.readAll()); + BlackMisc::Aviation::CFlightPlan + fp(equipmentIcao, originAirportIcao, destinationAirportIcao, alternateAirportIcao, + QDateTime::fromString(takeoffTimePlanned, "hhmm"), QDateTime::fromString(takeoffTimeActual, "hhmm"), + BlackMisc::PhysicalQuantities::CTime(enrouteTime, BlackMisc::PhysicalQuantities::CTimeUnit::hrmin()), + BlackMisc::PhysicalQuantities::CTime(fuelTime, BlackMisc::PhysicalQuantities::CTimeUnit::hrmin()), + BlackMisc::Aviation::CAltitude(cruiseAltitude, BlackMisc::Aviation::CAltitude::MeanSeaLevel, BlackMisc::PhysicalQuantities::CLengthUnit::ft()), + BlackMisc::PhysicalQuantities::CSpeed(cruiseTrueAirspeed, BlackMisc::PhysicalQuantities::CSpeedUnit::kts()), + flightRules, route, args.readAll()); emit sendFlightPlan(fp); } -void Client::sendFlightPlanQueryCmd(QTextStream &) +void Client::sendFlightPlanQueryCmd(QTextStream &args) { - emit sendFlightPlanQuery(); + QString callsign; + args >> callsign; + emit sendFlightPlanQuery(callsign); } void Client::sendServerQueryCmd(QTextStream &args) @@ -331,13 +334,13 @@ void Client::setOwnAircraftCmd(QTextStream &args) QString xpdrMode; args >> lat >> lon >> alt >> hdg >> pitch >> bank >> gs >> com1 >> com2 >> xpdrCode >> xpdrMode; BlackMisc::Aviation::CAircraft aircraft("", BlackMisc::Network::CUser(), BlackMisc::Aviation::CAircraftSituation( - BlackMisc::Geo::CCoordinateGeodetic(lat, lon, 0), - BlackMisc::Aviation::CAltitude(alt, BlackMisc::Aviation::CAltitude::MeanSeaLevel, BlackMisc::PhysicalQuantities::CLengthUnit::ft()), - BlackMisc::Aviation::CHeading(hdg, BlackMisc::Aviation::CHeading::True, BlackMisc::PhysicalQuantities::CAngleUnit::deg()), - BlackMisc::PhysicalQuantities::CAngle(pitch, BlackMisc::PhysicalQuantities::CAngleUnit::deg()), - BlackMisc::PhysicalQuantities::CAngle(bank, BlackMisc::PhysicalQuantities::CAngleUnit::deg()), - BlackMisc::PhysicalQuantities::CSpeed(gs, BlackMisc::PhysicalQuantities::CSpeedUnit::kts()) - )); + BlackMisc::Geo::CCoordinateGeodetic(lat, lon, 0), + BlackMisc::Aviation::CAltitude(alt, BlackMisc::Aviation::CAltitude::MeanSeaLevel, BlackMisc::PhysicalQuantities::CLengthUnit::ft()), + BlackMisc::Aviation::CHeading(hdg, BlackMisc::Aviation::CHeading::True, BlackMisc::PhysicalQuantities::CAngleUnit::deg()), + BlackMisc::PhysicalQuantities::CAngle(pitch, BlackMisc::PhysicalQuantities::CAngleUnit::deg()), + BlackMisc::PhysicalQuantities::CAngle(bank, BlackMisc::PhysicalQuantities::CAngleUnit::deg()), + BlackMisc::PhysicalQuantities::CSpeed(gs, BlackMisc::PhysicalQuantities::CSpeedUnit::kts()) + )); aircraft.setCom1System(BlackMisc::Aviation::CComSystem("COM1", BlackMisc::PhysicalQuantities::CFrequency(com1, BlackMisc::PhysicalQuantities::CFrequencyUnit::MHz()))); aircraft.setCom2System(BlackMisc::Aviation::CComSystem("COM2", BlackMisc::PhysicalQuantities::CFrequency(com2, BlackMisc::PhysicalQuantities::CFrequencyUnit::MHz()))); aircraft.setTransponder(BlackMisc::Aviation::CTransponder("Transponder", xpdrCode, xpdrMode)); @@ -351,7 +354,7 @@ void Client::setOwnAircraftPositionCmd(QTextStream &args) double alt; args >> lat >> lon >> alt; emit setOwnAircraftPosition(BlackMisc::Geo::CCoordinateGeodetic(lat, lon, 0), - BlackMisc::Aviation::CAltitude(alt, BlackMisc::Aviation::CAltitude::MeanSeaLevel, BlackMisc::PhysicalQuantities::CLengthUnit::ft())); + BlackMisc::Aviation::CAltitude(alt, BlackMisc::Aviation::CAltitude::MeanSeaLevel, BlackMisc::PhysicalQuantities::CLengthUnit::ft())); } void Client::setOwnAircraftSituationCmd(QTextStream &args) @@ -365,13 +368,13 @@ void Client::setOwnAircraftSituationCmd(QTextStream &args) double gs; args >> lat >> lon >> alt >> hdg >> pitch >> bank >> gs; emit setOwnAircraftSituation(BlackMisc::Aviation::CAircraftSituation( - BlackMisc::Geo::CCoordinateGeodetic(lat, lon, 0), - BlackMisc::Aviation::CAltitude(alt, BlackMisc::Aviation::CAltitude::MeanSeaLevel, BlackMisc::PhysicalQuantities::CLengthUnit::ft()), - BlackMisc::Aviation::CHeading(hdg, BlackMisc::Aviation::CHeading::True, BlackMisc::PhysicalQuantities::CAngleUnit::deg()), - BlackMisc::PhysicalQuantities::CAngle(pitch, BlackMisc::PhysicalQuantities::CAngleUnit::deg()), - BlackMisc::PhysicalQuantities::CAngle(bank, BlackMisc::PhysicalQuantities::CAngleUnit::deg()), - BlackMisc::PhysicalQuantities::CSpeed(gs, BlackMisc::PhysicalQuantities::CSpeedUnit::kts()) - )); + BlackMisc::Geo::CCoordinateGeodetic(lat, lon, 0), + BlackMisc::Aviation::CAltitude(alt, BlackMisc::Aviation::CAltitude::MeanSeaLevel, BlackMisc::PhysicalQuantities::CLengthUnit::ft()), + BlackMisc::Aviation::CHeading(hdg, BlackMisc::Aviation::CHeading::True, BlackMisc::PhysicalQuantities::CAngleUnit::deg()), + BlackMisc::PhysicalQuantities::CAngle(pitch, BlackMisc::PhysicalQuantities::CAngleUnit::deg()), + BlackMisc::PhysicalQuantities::CAngle(bank, BlackMisc::PhysicalQuantities::CAngleUnit::deg()), + BlackMisc::PhysicalQuantities::CSpeed(gs, BlackMisc::PhysicalQuantities::CSpeedUnit::kts()) + )); } void Client::setOwnAircraftAvionicsCmd(QTextStream &args) @@ -513,23 +516,24 @@ void Client::metarReplyReceived(const QString &data) std::cout << "METAR " << data.toStdString() << std::endl; } -void Client::flightPlanReplyReceived(const BlackMisc::Aviation::CFlightPlan &flightPlan) +void Client::flightPlanReplyReceived(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::Aviation::CFlightPlan &flightPlan) { std::string rules; switch (flightPlan.getFlightRules()) { - default: - case BlackMisc::Aviation::CFlightPlan::IFR: rules = "IFR"; break; - case BlackMisc::Aviation::CFlightPlan::VFR: rules = "VFR"; break; - case BlackMisc::Aviation::CFlightPlan::SVFR: rules = "SVFR"; break; + default: + case BlackMisc::Aviation::CFlightPlan::IFR: rules = "IFR"; break; + case BlackMisc::Aviation::CFlightPlan::VFR: rules = "VFR"; break; + case BlackMisc::Aviation::CFlightPlan::SVFR: rules = "SVFR"; break; } - std::cout << "FLIGHTPLAN " << flightPlan.getEquipmentIcao().toStdString() << " " << flightPlan.getOriginAirportIcao() << " " - << flightPlan.getDestinationAirportIcao() << " " << flightPlan.getAlternateAirportIcao() << " " - << flightPlan.getTakeoffTimePlannedHourMin().toStdString() << " " << flightPlan.getTakeoffTimeActualHourMin().toStdString() << " " - << flightPlan.getEnrouteTime() << " " << flightPlan.getFuelTime() << " " - << flightPlan.getCruiseAltitude() << " " << flightPlan.getCruiseTrueAirspeed() << " " << rules << " " - << flightPlan.getRoute().toStdString() << " " << flightPlan.getRemarks().toStdString() << "\n"; + std::cout << "FLIGHTPLAN " << callsign + << flightPlan.getEquipmentIcao().toStdString() << " " << flightPlan.getOriginAirportIcao() << " " + << flightPlan.getDestinationAirportIcao() << " " << flightPlan.getAlternateAirportIcao() << " " + << flightPlan.getTakeoffTimePlannedHourMin().toStdString() << " " << flightPlan.getTakeoffTimeActualHourMin().toStdString() << " " + << flightPlan.getEnrouteTime() << " " << flightPlan.getFuelTime() << " " + << flightPlan.getCruiseAltitude() << " " << flightPlan.getCruiseTrueAirspeed() << " " << rules << " " + << flightPlan.getRoute().toStdString() << " " << flightPlan.getRemarks().toStdString() << "\n"; } void Client::pilotDisconnected(const BlackMisc::Aviation::CCallsign &callsign) @@ -565,5 +569,5 @@ void Client::customPacketReceived(const BlackMisc::Aviation::CCallsign &callsign void Client::statusMessage(const BlackMisc::CStatusMessage &message) { std::cout << "STATUS " << message.getSeverityAsString().toStdString() << " " << message.getTypeAsString().toStdString() << " " - << message.getMessage().toStdString() << "\n"; + << message.getMessage().toStdString() << "\n"; } diff --git a/samples/cli_client/client.h b/samples/cli_client/client.h index ee6bcf302..373ed1bcd 100644 --- a/samples/cli_client/client.h +++ b/samples/cli_client/client.h @@ -74,7 +74,7 @@ signals: //to send to INetwork void sendAtcQuery(const BlackMisc::Aviation::CCallsign &callsign); void sendAtisQuery(const BlackMisc::Aviation::CCallsign &callsign); void sendFlightPlan(const BlackMisc::Aviation::CFlightPlan &fp); - void sendFlightPlanQuery(); + void sendFlightPlanQuery(const BlackMisc::Aviation::CCallsign &callsign); void sendRealNameQuery(const BlackMisc::Aviation::CCallsign &callsign); void sendCapabilitiesQuery(const BlackMisc::Aviation::CCallsign &callsign); void sendIcaoCodesQuery(const BlackMisc::Aviation::CCallsign &callsign); @@ -103,7 +103,7 @@ public slots: //to receive from INetwork void capabilitiesReplyReceived(const BlackMisc::Aviation::CCallsign &callsign, quint32 flags); void kicked(const QString &msg); void metarReplyReceived(const QString &data); - void flightPlanReplyReceived(const BlackMisc::Aviation::CFlightPlan &flightPlan); + void flightPlanReplyReceived(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::Aviation::CFlightPlan &flightPlan); void pilotDisconnected(const BlackMisc::Aviation::CCallsign &callsign); void icaoCodesReplyReceived(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::Aviation::CAircraftIcao &icaoData); void pongReceived(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::PhysicalQuantities::CTime &elapsedTime); diff --git a/src/blackcore/network.h b/src/blackcore/network.h index 06617e73c..b087290f1 100644 --- a/src/blackcore/network.h +++ b/src/blackcore/network.h @@ -251,7 +251,7 @@ namespace BlackCore * \pre Network must be connected when calling this function. * \sa flightPlanReplyReceived */ - virtual void sendFlightPlanQuery() = 0; + virtual void sendFlightPlanQuery(const BlackMisc::Aviation::CCallsign &callsign) = 0; //! @} //////////////////////////////////////////////////////////////// @@ -320,7 +320,7 @@ namespace BlackCore * \pre Network must be connected when calling this function. * \sa metarReplyReceived */ - virtual void sendMetarQuery(const QString &airportICAO) = 0; + virtual void sendMetarQuery(const BlackMisc::Aviation::CAirportIcao &airportIcao) = 0; /*! * Send a message querying the weather data for the airport with a specific ICAO code. @@ -329,7 +329,7 @@ namespace BlackCore * \sa windDataReplyReceived * \sa cloudDataReplyReceived */ - virtual void sendWeatherDataQuery(const QString &airportICAO) = 0; + virtual void sendWeatherDataQuery(const BlackMisc::Aviation::CAirportIcao &airportIcao) = 0; signals: //! @} @@ -377,7 +377,7 @@ namespace BlackCore * We received a reply to one of our flight plan queries, containing our up-to-date flight plan. * \sa sendFlightPlanQuery */ - void flightPlanReplyReceived(const BlackMisc::Aviation::CFlightPlan &flightPlan); + void flightPlanReplyReceived(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::Aviation::CFlightPlan &flightPlan); //! @} //////////////////////////////////////////////////////////////// diff --git a/src/blackcore/network_vatlib.cpp b/src/blackcore/network_vatlib.cpp index eb082d70a..8db00c175 100644 --- a/src/blackcore/network_vatlib.cpp +++ b/src/blackcore/network_vatlib.cpp @@ -390,7 +390,7 @@ namespace BlackCore void CNetworkVatlib::presetIcaoCodes(const BlackMisc::Aviation::CAircraftIcao &icao) { Q_ASSERT_X(isDisconnected(), "CNetworkVatlib", "Can't change ICAO codes while still connected"); - m_icaoCodes = icao; + m_icaoCode = icao; } void CNetworkVatlib::presetLoginMode(LoginMode mode) @@ -617,20 +617,28 @@ namespace BlackCore { Cvatlib_Network::FlightPlan vatlibFP; QString route = QString(flightPlan.getRoute()).replace(" ", "."); - QString remarks = QString(flightPlan.getRemarks()).replace(":", ";"); - remarks.truncate(100); + QString remarks = QString(flightPlan.getRemarks()).replace(":", ";").trimmed(); + QString alt = flightPlan.getCruiseAltitude().isFlightLevel() ? + flightPlan.getCruiseAltitude().toQString() : + flightPlan.getCruiseAltitude().valueRoundedWithUnit(0); + alt = alt.remove('.').remove(','); // remove any separators + QByteArray acTypeTemp, altAptTemp, cruiseAltTemp, depAptTemp, destAptTemp, routeTemp, remarksTemp; vatlibFP.acType = acTypeTemp = toFSD(flightPlan.getEquipmentIcao()); vatlibFP.altApt = altAptTemp = toFSD(flightPlan.getAlternateAirportIcao().asString()); - vatlibFP.cruiseAlt = cruiseAltTemp = toFSD(QByteArray::number(flightPlan.getCruiseAltitude().value(CLengthUnit::ft()), 'f', 0)); + vatlibFP.cruiseAlt = cruiseAltTemp = toFSD(alt); vatlibFP.depApt = depAptTemp = toFSD(flightPlan.getOriginAirportIcao().asString()); vatlibFP.depTimeActual = flightPlan.getTakeoffTimeActual().toUTC().toString("hhmm").toInt(); vatlibFP.depTimePlanned = flightPlan.getTakeoffTimePlanned().toUTC().toString("hhmm").toInt(); vatlibFP.destApt = destAptTemp = toFSD(flightPlan.getDestinationAirportIcao().asString()); - vatlibFP.enrouteHrs = flightPlan.getEnrouteTime().valueRounded(CTimeUnit::h(), 0); - vatlibFP.enrouteMins = int(flightPlan.getEnrouteTime().valueRounded(CTimeUnit::hrmin(), 0)) % 60; - vatlibFP.fuelHrs = flightPlan.getFuelTime().valueRounded(CTimeUnit::h(), 0); - vatlibFP.fuelMins = int(flightPlan.getFuelTime().valueRounded(CTimeUnit::hrmin(), 0)) % 60; + + QList timeParts = flightPlan.getEnrouteTime().getHrsMinSecParts(); + vatlibFP.enrouteHrs = timeParts[CTime::Hours]; + vatlibFP.enrouteMins = timeParts[CTime::Minutes]; + + timeParts = flightPlan.getFuelTime().getHrsMinSecParts(); + vatlibFP.fuelHrs = timeParts[CTime::Hours]; + vatlibFP.fuelMins = timeParts[CTime::Minutes]; vatlibFP.remarks = remarksTemp = toFSD(remarks); vatlibFP.route = routeTemp = toFSD(route); vatlibFP.trueCruiseSpeed = flightPlan.getCruiseTrueAirspeed().valueRounded(CSpeedUnit::kts()); @@ -646,13 +654,13 @@ namespace BlackCore catch (...) { exceptionDispatcher(Q_FUNC_INFO); } } - void CNetworkVatlib::sendFlightPlanQuery() + void CNetworkVatlib::sendFlightPlanQuery(const BlackMisc::Aviation::CCallsign &callsign) { Q_ASSERT_X(isConnected(), "CNetworkVatlib", "Can't send to server when disconnected"); try { - m_net->SendInfoQuery(Cvatlib_Network::infoQuery_FP, toFSD(m_callsign)); + m_net->SendInfoQuery(Cvatlib_Network::infoQuery_FP, toFSD(callsign)); } catch (...) { exceptionDispatcher(Q_FUNC_INFO); } } @@ -713,21 +721,21 @@ namespace BlackCore { try { - const QByteArray acTypeICAObytes = toFSD(m_icaoCodes.getAircraftDesignator()); - const QByteArray airlineICAObytes = toFSD(m_icaoCodes.getAirlineDesignator()); - const QByteArray liverybytes = toFSD(m_icaoCodes.getLivery()); + const QByteArray acTypeICAObytes = toFSD(m_icaoCode.getAircraftDesignator()); + const QByteArray airlineICAObytes = toFSD(m_icaoCode.getAirlineDesignator()); + const QByteArray liverybytes = toFSD(m_icaoCode.getLivery()); std::vector keysValues; - if (!m_icaoCodes.getAircraftDesignator().isEmpty()) + if (!m_icaoCode.getAircraftDesignator().isEmpty()) { keysValues.push_back(m_net->acinfo_Equipment); keysValues.push_back(acTypeICAObytes); } - if (m_icaoCodes.hasAirlineDesignator()) + if (m_icaoCode.hasAirlineDesignator()) { keysValues.push_back(m_net->acinfo_Airline); keysValues.push_back(airlineICAObytes); } - if (m_icaoCodes.hasLivery()) + if (m_icaoCode.hasLivery()) { keysValues.push_back(m_net->acinfo_Livery); keysValues.push_back(liverybytes); @@ -749,24 +757,24 @@ namespace BlackCore catch (...) { exceptionDispatcher(Q_FUNC_INFO); } } - void CNetworkVatlib::sendMetarQuery(const QString &airportICAO) + void CNetworkVatlib::sendMetarQuery(const BlackMisc::Aviation::CAirportIcao &airportIcao) { Q_ASSERT_X(isConnected(), "CNetworkVatlib", "Can't send to server when disconnected"); try { - m_net->RequestMetar(toFSD(airportICAO)); + m_net->RequestMetar(toFSD(airportIcao.asString())); } catch (...) { exceptionDispatcher(Q_FUNC_INFO); } } - void CNetworkVatlib::sendWeatherDataQuery(const QString &airportICAO) + void CNetworkVatlib::sendWeatherDataQuery(const BlackMisc::Aviation::CAirportIcao &airportIcao) { Q_ASSERT_X(isConnected(), "CNetworkVatlib", "Can't send to server when disconnected"); try { - m_net->RequestWeatherData(toFSD(airportICAO)); + m_net->RequestWeatherData(toFSD(airportIcao.asString())); } catch (...) { exceptionDispatcher(Q_FUNC_INFO); } } @@ -998,11 +1006,6 @@ namespace BlackCore void CNetworkVatlib::onFlightPlanReceived(Cvatlib_Network *, const char *callsign, Cvatlib_Network::FlightPlan fp, void *cbvar) { - if (cbvar_cast(cbvar)->m_callsign != cbvar_cast(cbvar)->fromFSD(callsign)) - { - return; // ignore other pilots' flightplans - } - BlackMisc::Aviation::CFlightPlan::FlightRules rules = BlackMisc::Aviation::CFlightPlan::VFR; switch (fp.fpRules) { @@ -1013,20 +1016,25 @@ namespace BlackCore } auto cruiseAltString = cbvar_cast(cbvar)->fromFSD(fp.cruiseAlt); - if (! cruiseAltString.contains(QRegExp("[A-Z][a-z]"))) + static const QRegExp withUnit("\\D+"); + if (!cruiseAltString.isEmpty() && withUnit.indexIn(cruiseAltString) < 0) { cruiseAltString += "ft"; } BlackMisc::Aviation::CAltitude cruiseAlt; cruiseAlt.parseFromString(cruiseAltString); + + QString depTimePlanned = QString("0000").append(QString::number(fp.depTimePlanned)).right(4); + QString depTimeActual = QString("0000").append(QString::number(fp.depTimeActual)).right(4); + BlackMisc::Aviation::CFlightPlan flightPlan( cbvar_cast(cbvar)->fromFSD(fp.acType), cbvar_cast(cbvar)->fromFSD(fp.depApt), cbvar_cast(cbvar)->fromFSD(fp.destApt), cbvar_cast(cbvar)->fromFSD(fp.altApt), - QDateTime::fromString(QString::number(fp.depTimePlanned), "hhmm"), - QDateTime::fromString(QString::number(fp.depTimeActual), "hhmm"), + QDateTime::fromString(depTimePlanned, "hhmm"), + QDateTime::fromString(depTimeActual, "hhmm"), BlackMisc::PhysicalQuantities::CTime(fp.enrouteHrs * 60 + fp.enrouteMins, BlackMisc::PhysicalQuantities::CTimeUnit::min()), BlackMisc::PhysicalQuantities::CTime(fp.fuelHrs * 60 + fp.fuelMins, BlackMisc::PhysicalQuantities::CTimeUnit::min()), cruiseAlt, @@ -1036,7 +1044,7 @@ namespace BlackCore cbvar_cast(cbvar)->fromFSD(fp.remarks) ); - emit cbvar_cast(cbvar)->flightPlanReplyReceived(flightPlan); + emit cbvar_cast(cbvar)->flightPlanReplyReceived(callsign, flightPlan); } void CNetworkVatlib::onTemperatureDataReceived(Cvatlib_Network *, Cvatlib_Network::TempLayer /** layers **/ [4], INT /** pressure **/, void * /** cbvar **/) diff --git a/src/blackcore/network_vatlib.h b/src/blackcore/network_vatlib.h index 3003f90c5..4cf02baab 100644 --- a/src/blackcore/network_vatlib.h +++ b/src/blackcore/network_vatlib.h @@ -3,10 +3,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -/*! - \file -*/ - #ifndef BLACKCORE_NETWORK_VATLIB_H #define BLACKCORE_NETWORK_VATLIB_H @@ -64,7 +60,7 @@ namespace BlackCore virtual void sendAtcQuery(const BlackMisc::Aviation::CCallsign &callsign) override; virtual void sendAtisQuery(const BlackMisc::Aviation::CCallsign &callsign) override; virtual void sendFlightPlan(const BlackMisc::Aviation::CFlightPlan &flightPlan) override; - virtual void sendFlightPlanQuery() override; + virtual void sendFlightPlanQuery(const BlackMisc::Aviation::CCallsign &callsign) override; // Aircraft slots virtual void sendCapabilitiesQuery(const BlackMisc::Aviation::CCallsign &callsign) override; @@ -79,14 +75,11 @@ namespace BlackCore const BlackMisc::Aviation::CTransponder &xpdr) override; // Weather slots - virtual void sendMetarQuery(const QString &airportICAO) override; - virtual void sendWeatherDataQuery(const QString &airportICAO) override; + virtual void sendMetarQuery(const BlackMisc::Aviation::CAirportIcao &airportIcao) override; + virtual void sendWeatherDataQuery(const BlackMisc::Aviation::CAirportIcao &airportIcao) override; // some helper methods - //! - - /*! * \brief Create the data load for FSIPI(R) packages / FsInn * \details FSIPI(R) queries @@ -171,7 +164,7 @@ namespace BlackCore Cvatlib_Network::connStatus m_status; BlackMisc::Network::CServer m_server; BlackMisc::Aviation::CCallsign m_callsign; - BlackMisc::Aviation::CAircraftIcao m_icaoCodes; + BlackMisc::Aviation::CAircraftIcao m_icaoCode; BlackMisc::Aviation::CAircraft m_ownAircraft; // not using callsign, user, or icao parts of this member because they can't be changed when connected QMap m_atisParts; diff --git a/src/blackgui/flightplancomponent.cpp b/src/blackgui/flightplancomponent.cpp index 520bf4b8e..5de69df35 100644 --- a/src/blackgui/flightplancomponent.cpp +++ b/src/blackgui/flightplancomponent.cpp @@ -3,6 +3,7 @@ using namespace BlackMisc; using namespace BlackMisc::Aviation; +using namespace BlackMisc::PhysicalQuantities; namespace BlackGui { @@ -11,7 +12,7 @@ namespace BlackGui { ui->setupUi(this); connect(this->ui->pb_Send, &QPushButton::pressed, this, &CFlightPlanComponent::sendFlightPlan); - connect(this->ui->pb_Load, &QPushButton::pressed, this, &CFlightPlanComponent::loadFlightPlan); + connect(this->ui->pb_Load, &QPushButton::pressed, this, &CFlightPlanComponent::loadFlightPlanFromNetwork); connect(this->ui->pb_Reset, &QPushButton::pressed, this, &CFlightPlanComponent::resetFlightPlan); connect(this->ui->pb_ValidateFlightPlan, &QPushButton::pressed, this, &CFlightPlanComponent::validateFlightPlan); @@ -56,7 +57,7 @@ namespace BlackGui this->ui->le_PilotsName->setText(aircraftData.getPilot().getRealName()); } - void CFlightPlanComponent::prefillWithFlightPlanData(const BlackMisc::Aviation::CFlightPlan &flightPlan) + void CFlightPlanComponent::fillWithFlightPlanData(const BlackMisc::Aviation::CFlightPlan &flightPlan) { this->ui->le_AlternateAirport->setText(flightPlan.getAlternateAirportIcao().asString()); this->ui->le_DestinationAirport->setText(flightPlan.getAlternateAirportIcao().asString()); @@ -66,8 +67,13 @@ namespace BlackGui this->ui->le_TakeOffTimePlanned->setText(flightPlan.getTakeoffTimePlannedHourMin()); this->ui->le_FuelOnBoard->setText(flightPlan.getFuelTimeHourMin()); this->ui->le_EstimatedTimeEnroute->setText(flightPlan.getEnrouteTimeHourMin()); - this->ui->le_CrusingAltitude->setText(flightPlan.getCruiseAltitude().toQString()); this->ui->le_CruiseTrueAirspeed->setText(flightPlan.getCruiseTrueAirspeed().valueRoundedWithUnit(BlackMisc::PhysicalQuantities::CSpeedUnit::kts(), 0)); + + CAltitude cruiseAlt = flightPlan.getCruiseAltitude(); + if (cruiseAlt.isFlightLevel()) + this->ui->le_CrusingAltitude->setText(cruiseAlt.toQString()); + else + this->ui->le_CrusingAltitude->setText(cruiseAlt.valueRoundedWithUnit(BlackMisc::PhysicalQuantities::CLengthUnit::ft(), 0)); } CFlightPlan CFlightPlanComponent::getFlightPlan() const @@ -97,16 +103,26 @@ namespace BlackGui v = ui->pte_Route->toPlainText().trimmed(); if (v.isEmpty()) { - QString m = QString("Missing %1").arg(this->ui->lbl_Route->text()); + QString m = QString("Missing flight plan route"); + messages.push_back(CStatusMessage::getValidationError(m)); + } + else if (v.length() > CFlightPlan::MaxRouteLength) + { + QString m = QString("Flight plan route length exceeded (%1 chars max.)").arg(CFlightPlan::MaxRouteLength); messages.push_back(CStatusMessage::getValidationError(m)); } else flightPlan.setRoute(v); v = ui->pte_Remarks->toPlainText().trimmed(); - if (v.length() > 100) + if (v.isEmpty()) { - QString m = QString("Length exceeded (100 chars max.) %1").arg(this->ui->lbl_Remarks->text()); + QString m = QString("No remarks, voice capabilities are mandatory"); + messages.push_back(CStatusMessage::getValidationError(m)); + } + else if (v.length() > CFlightPlan::MaxRemarksLength) + { + QString m = QString("Flight plan remarks length exceeded (%1 chars max.)").arg(CFlightPlan::MaxRemarksLength); messages.push_back(CStatusMessage::getValidationError(m)); } else @@ -139,8 +155,15 @@ namespace BlackGui else flightPlan.setTakeoffTimePlanned(v); + static const QRegExp withUnit("\\D+"); v = ui->le_CrusingAltitude->text().trimmed(); - CAltitude cruisingAltitude(v); + if (!v.isEmpty() && withUnit.indexIn(v) < 0) + { + v += "ft"; + this->ui->le_CrusingAltitude->setText(v); + } + + CAltitude cruisingAltitude(v, CPqString::SeparatorsLocale); if (v.isEmpty() || cruisingAltitude.isNull()) { QString m = QString("Wrong %1").arg(this->ui->lbl_CrusingAltitude->text()); @@ -171,7 +194,7 @@ namespace BlackGui v = this->ui->le_CruiseTrueAirspeed->text(); BlackMisc::PhysicalQuantities::CSpeed cruiseTAS; - cruiseTAS.parseFromString(v); + cruiseTAS.parseFromString(v, CPqString::SeparatorsLocale); if (cruiseTAS.isNull()) { QString m = QString("Wrong TAS, %1").arg(this->ui->lbl_CruiseTrueAirspeed->text()); @@ -204,14 +227,14 @@ namespace BlackGui CStatusMessage m; if (this->getIContextNetwork()->isConnected()) { - flightPlan.setWhenLastSent(QDateTime::currentDateTimeUtc()); + flightPlan.setWhenLastSentOrLoaded(QDateTime::currentDateTimeUtc()); this->getIContextNetwork()->sendFlightPlan(flightPlan); - this->ui->le_LastSent->setText(flightPlan.whenLastSent().toString()); + this->ui->le_LastSent->setText(flightPlan.whenLastSentOrLoaded().toString()); m = CStatusMessage::getInfoMessage("Sent flight plan", CStatusMessage::TypeTrafficNetwork); } else { - flightPlan.setWhenLastSent(QDateTime()); + flightPlan.setWhenLastSentOrLoaded(QDateTime()); // empty this->ui->le_LastSent->clear(); m = CStatusMessage::getErrorMessage("No errors, but not connected, cannot send flight plan", CStatusMessage::TypeTrafficNetwork); } @@ -258,9 +281,30 @@ namespace BlackGui this->ui->le_TakeOffTimePlanned->setText(QDateTime::currentDateTimeUtc().addSecs(30 * 60).toString("hh:mm")); } - void CFlightPlanComponent::loadFlightPlan() + void CFlightPlanComponent::loadFlightPlanFromNetwork() { + if (!this->getIContextNetwork()) + { + this->sendStatusMessage(CStatusMessage::getInfoMessage("Cannot load flight plan, network not available", CStatusMessage::TypeTrafficNetwork)); + return; + } + if (!this->getIContextNetwork()->isConnected()) + { + this->sendStatusMessage(CStatusMessage::getWarningMessage("Cannot load flight plan, network not connected", CStatusMessage::TypeTrafficNetwork)); + return; + } + CAircraft ownAircraft = this->getIContextOwnAircraft()->getOwnAircraft(); + CFlightPlan loadedPlan = this->getIContextNetwork()->loadFlightPlanFromNetwork(ownAircraft.getCallsign()); + if (loadedPlan.wasSentOrLoaded()) + { + this->fillWithFlightPlanData(loadedPlan); + this->sendStatusMessage(CStatusMessage::getInfoMessage("Updated with loaded flight plan", CStatusMessage::TypeTrafficNetwork)); + } + else + { + this->sendStatusMessage(CStatusMessage::getWarningMessage("No flight plan data", CStatusMessage::TypeTrafficNetwork)); + } } void CFlightPlanComponent::buildRemarkString() diff --git a/src/blackgui/flightplancomponent.h b/src/blackgui/flightplancomponent.h index f1170b70e..c232cd614 100644 --- a/src/blackgui/flightplancomponent.h +++ b/src/blackgui/flightplancomponent.h @@ -27,7 +27,7 @@ namespace BlackGui void prefillWithAircraftData(const BlackMisc::Aviation::CAircraft &aircraftData); //! Prefill with aircraft dara - void prefillWithFlightPlanData(const BlackMisc::Aviation::CFlightPlan &flightPlan); + void fillWithFlightPlanData(const BlackMisc::Aviation::CFlightPlan &flightPlan); //! Get this flight plan BlackMisc::Aviation::CFlightPlan getFlightPlan() const; @@ -55,7 +55,7 @@ namespace BlackGui void resetFlightPlan(); //! Load Flightplan - void loadFlightPlan(); + void loadFlightPlanFromNetwork(); //! Validate Flightplan void validateFlightPlan(); diff --git a/src/blackmisc/avaltitude.cpp b/src/blackmisc/avaltitude.cpp index 9e5f6a337..99adfd5ec 100644 --- a/src/blackmisc/avaltitude.cpp +++ b/src/blackmisc/avaltitude.cpp @@ -17,15 +17,15 @@ namespace BlackMisc /* * Constructor */ - CAltitude::CAltitude(const QString &altitudeAsString) : BlackMisc::PhysicalQuantities::CLength(0, BlackMisc::PhysicalQuantities::CLengthUnit::m()), m_datum(MeanSeaLevel) + CAltitude::CAltitude(const QString &altitudeAsString, BlackMisc::PhysicalQuantities::CPqString::SeparatorMode mode) : BlackMisc::PhysicalQuantities::CLength(0, BlackMisc::PhysicalQuantities::CLengthUnit::m()), m_datum(MeanSeaLevel) { - this->parseFromString(altitudeAsString); + this->parseFromString(altitudeAsString, mode); } /* * Own implementation for streaming */ - QString CAltitude::convertToQString(bool /* i18n */) const + QString CAltitude::convertToQString(bool i18n) const { if (this->m_datum == FlightLevel) { @@ -34,7 +34,7 @@ namespace BlackMisc } else { - QString s = this->CLength::convertToQString(); + QString s = this->CLength::valueRoundedWithUnit(CLengthUnit::ft(), i18n); return s.append(this->isMeanSeaLevel() ? " MSL" : " AGL"); } } @@ -156,6 +156,14 @@ namespace BlackMisc * Parse value */ void CAltitude::parseFromString(const QString &value) + { + this->parseFromString(value, BlackMisc::PhysicalQuantities::CPqString::SeparatorsCLocale); + } + + /* + * Parse value + */ + void CAltitude::parseFromString(const QString &value, BlackMisc::PhysicalQuantities::CPqString::SeparatorMode mode) { QString v = value.trimmed(); @@ -184,7 +192,7 @@ namespace BlackMisc rd = AboveGround; } - CLength l = BlackMisc::PhysicalQuantities::CPqString::parse(v); + CLength l = BlackMisc::PhysicalQuantities::CPqString::parse(v, mode); *this = CAltitude(l, rd); } diff --git a/src/blackmisc/avaltitude.h b/src/blackmisc/avaltitude.h index 3ea4be186..8d8cceb6e 100644 --- a/src/blackmisc/avaltitude.h +++ b/src/blackmisc/avaltitude.h @@ -64,7 +64,7 @@ namespace BlackMisc CAltitude(double value, ReferenceDatum datum, const BlackMisc::PhysicalQuantities::CLengthUnit &unit) : BlackMisc::PhysicalQuantities::CLength(value, unit), m_datum(datum) {} //! Altitude as string - CAltitude(const QString &altitudeAsString); + CAltitude(const QString &altitudeAsString, BlackMisc::PhysicalQuantities::CPqString::SeparatorMode mode = BlackMisc::PhysicalQuantities::CPqString::SeparatorsLocale); //! Constructor by CLength CAltitude(BlackMisc::PhysicalQuantities::CLength altitude, ReferenceDatum datum) : BlackMisc::PhysicalQuantities::CLength(altitude), m_datum(datum) {} @@ -102,9 +102,12 @@ namespace BlackMisc //! \copydoc CValueObject::fromJson void fromJson(const QJsonObject &json) override; - //! \copydoc CValueObject::parseFromString + //! \copydoc CValueObject::parseFromString(const QString &value) void parseFromString(const QString &value) override; + //! \copydoc CValueObject::parseFromString(const QString &value, BlackMisc::PhysicalQuantities::CPqString::SeparatorMode mode) + void parseFromString(const QString &value, BlackMisc::PhysicalQuantities::CPqString::SeparatorMode mode) override; + //! Register metadata static void registerMetadata(); diff --git a/src/blackmisc/avflightplan.h b/src/blackmisc/avflightplan.h index 13e38c0e9..a01405050 100644 --- a/src/blackmisc/avflightplan.h +++ b/src/blackmisc/avflightplan.h @@ -37,6 +37,9 @@ namespace BlackMisc SVFR //!< Special VFR (reserved for ATC use) }; + static const int MaxRemarksLength = 150; //!< Max remarks length + static const int MaxRouteLength = 150; //!< Max route length + /*! * Default constructor */ @@ -50,8 +53,12 @@ namespace BlackMisc const CAltitude &cruiseAltitude, const PhysicalQuantities::CSpeed &cruiseTrueAirspeed, FlightRules flightRules, const QString &route, const QString &remarks) : m_equipmentIcao(equipmentIcao), m_originAirportIcao(originAirportIcao), m_destinationAirportIcao(destinationAirportIcao), m_alternateAirportIcao(alternateAirportIcao), m_takeoffTimePlanned(takeoffTimePlanned), m_takeoffTimeActual(takeoffTimeActual), m_enrouteTime(enrouteTime), m_fuelTime(fuelTime), - m_cruiseAltitude(cruiseAltitude), m_cruiseTrueAirspeed(cruiseTrueAirspeed), m_flightRules(flightRules), m_route(route), m_remarks(remarks.left(100)) - {} + m_cruiseAltitude(cruiseAltitude), m_cruiseTrueAirspeed(cruiseTrueAirspeed), m_flightRules(flightRules), + m_route(route.trimmed().left(MaxRouteLength).toUpper()), m_remarks(remarks.trimmed().left(MaxRemarksLength).toUpper()) + { + m_enrouteTime.switchUnit(BlackMisc::PhysicalQuantities::CTimeUnit::hrmin()); + m_fuelTime.switchUnit(BlackMisc::PhysicalQuantities::CTimeUnit::hrmin()); + } //! Set ICAO aircraft equipment code string (e.g. "T/A320/F") void setEquipmentIcao(const QString &equipmentIcao) { m_equipmentIcao = equipmentIcao; } @@ -87,10 +94,10 @@ namespace BlackMisc void setTakeoffTimeActual(QString time) { m_takeoffTimeActual = QDateTime::currentDateTimeUtc(); m_takeoffTimeActual.setTime(QTime::fromString(time, "hh:mm"));} //! Set planned enroute flight time - void setEnrouteTime(const PhysicalQuantities::CTime &enrouteTime) { m_enrouteTime = enrouteTime; } + void setEnrouteTime(const PhysicalQuantities::CTime &enrouteTime) { m_enrouteTime = enrouteTime; m_enrouteTime.switchUnit(BlackMisc::PhysicalQuantities::CTimeUnit::hrmin());} //! Set amount of fuel load in time - void setFuelTime(const PhysicalQuantities::CTime &fuelTime) { m_fuelTime = fuelTime; } + void setFuelTime(const PhysicalQuantities::CTime &fuelTime) { m_fuelTime = fuelTime; m_fuelTime.switchUnit(BlackMisc::PhysicalQuantities::CTimeUnit::hrmin());} //! Set amount of fuel load in time hh:mm void setFuelTime(const QString &fuelTime) { m_fuelTime = PhysicalQuantities::CTime(fuelTime); } @@ -105,13 +112,13 @@ namespace BlackMisc void setFlightRule(FlightRules flightRules) { m_flightRules = flightRules; } //! Set route string - void setRoute(const QString &route) { m_route = route; } + void setRoute(const QString &route) { m_route = route.trimmed().left(MaxRouteLength).toUpper(); } //! Set remarks string (max 100 characters) - void setRemarks(const QString &remarks) { m_remarks = remarks.left(100); } + void setRemarks(const QString &remarks) { m_remarks = remarks.trimmed().left(MaxRemarksLength).toUpper(); } //! When last sent - void setWhenLastSent(const QDateTime &dateTime) { m_lastSent = dateTime; } + void setWhenLastSentOrLoaded(const QDateTime &dateTime) { m_lastSentOrLoaded = dateTime; } //! Get ICAO aircraft equipment code string const QString &getEquipmentIcao() const { return m_equipmentIcao; } @@ -147,7 +154,7 @@ namespace BlackMisc const PhysicalQuantities::CTime &getFuelTime() const { return m_fuelTime; } //! Get amount of fuel load in time - QString getFuelTimeHourMin() const { return m_enrouteTime.valueRoundedWithUnit(BlackMisc::PhysicalQuantities::CTimeUnit::hrmin()); } + QString getFuelTimeHourMin() const { return m_fuelTime.valueRoundedWithUnit(BlackMisc::PhysicalQuantities::CTimeUnit::hrmin()); } //! Cruising altitudes const BlackMisc::Aviation::CAltitude &getCruiseAltitude() const { return m_cruiseAltitude; } @@ -162,10 +169,16 @@ namespace BlackMisc const QString &getRoute() const { return m_route; } //! When last sent - const QDateTime &whenLastSent() const { return m_lastSent; } + const QDateTime &whenLastSentOrLoaded() const { return m_lastSentOrLoaded; } //! Flight plan already sent - bool wasSent() const { return m_lastSent.isValid() && !m_lastSent.isNull(); } + bool wasSentOrLoaded() const { return m_lastSentOrLoaded.isValid() && !m_lastSentOrLoaded.isNull(); } + + //! \brief Received before n ms + qint64 timeDiffSentOrLoadedMs() const + { + return this->m_lastSentOrLoaded.msecsTo(QDateTime::currentDateTimeUtc()); + } //! Get remarks string const QString &getRemarks() const { return m_remarks; } @@ -219,13 +232,13 @@ namespace BlackMisc FlightRules m_flightRules; QString m_route; QString m_remarks; - QDateTime m_lastSent; + QDateTime m_lastSentOrLoaded; }; } // namespace } // namespace Q_DECLARE_METATYPE(BlackMisc::Aviation::CFlightPlan) BLACK_DECLARE_TUPLE_CONVERSION(BlackMisc::Aviation::CFlightPlan, (o.m_equipmentIcao, o.m_originAirportIcao, o.m_destinationAirportIcao, o.m_alternateAirportIcao, - o.m_takeoffTimePlanned, o.m_takeoffTimeActual, o.m_enrouteTime, o.m_fuelTime, o.m_cruiseAltitude, tie(o.m_cruiseTrueAirspeed, o.m_flightRules, o.m_route, o.m_remarks, o.m_lastSent))) + o.m_takeoffTimePlanned, o.m_takeoffTimeActual, o.m_enrouteTime, o.m_fuelTime, o.m_cruiseAltitude, tie(o.m_cruiseTrueAirspeed, o.m_flightRules, o.m_route, o.m_remarks, o.m_lastSentOrLoaded))) #endif // guard diff --git a/src/blackmisc/pqphysicalquantity.h b/src/blackmisc/pqphysicalquantity.h index 4de445395..20deb213e 100644 --- a/src/blackmisc/pqphysicalquantity.h +++ b/src/blackmisc/pqphysicalquantity.h @@ -234,10 +234,16 @@ namespace BlackMisc //! \copydoc CValueObject::fromJson virtual void fromJson(const QJsonObject &json) override; + //! Parse to string, with specified separator + virtual void parseFromString(const QString &value, CPqString::SeparatorMode mode) + { + this->parseFromString(value, mode); + } + //! \copydoc CValueObject::parseFromString virtual void parseFromString(const QString &value) override { - *this = CPqString::parse(value); + *this = CPqString::parse(value, CPqString::SeparatorsCLocale); } //! Register metadata of unit and quantity diff --git a/src/blackmisc/pqstring.cpp b/src/blackmisc/pqstring.cpp index fbd1236ea..5893a49b3 100644 --- a/src/blackmisc/pqstring.cpp +++ b/src/blackmisc/pqstring.cpp @@ -93,17 +93,36 @@ namespace BlackMisc /* * Parse */ - QVariant CPqString::parseToVariant(const QString &value) + QVariant CPqString::parseToVariant(const QString &value, SeparatorMode mode) { + static QRegExp rx("([0-9]+)\\s*(\\D*)$"); QVariant v; if (value.isEmpty()) return v; - QRegExp rx("^([-+]?[0-9]*\\.?[0-9]+)\\s*(\\D*)$"); - if (rx.indexIn(value) < 0) return v; - QString number = rx.cap(1).trimmed(); + + if (rx.indexIn(value) < 0) return v; // not a valid number QString unit = rx.cap(2).trimmed(); + QString number = QString(value).replace(unit, ""); + unit = unit.trimmed(); // trim after replace, not before + if (unit.isEmpty() || number.isEmpty()) return v; bool success; - double numberD = number.toDouble(&success); + double numberD; + switch (mode) + { + case SeparatorsLocale: + numberD = QLocale::system().toDouble(number, &success); + break; + case SeparatorsCLocale: + numberD = number.toDouble(&success); + break; + case SeparatorsBestGuess: + numberD = number.toDouble(&success); + if (!success) numberD = QLocale::system().toDouble(number, &success); + break; + default: + qFatal("Wrong mode"); + break; + } if (!success) return v; if (CMeasurementUnit::isValidUnitSymbol(unit)) diff --git a/src/blackmisc/pqstring.h b/src/blackmisc/pqstring.h index 0dfbe27f3..2d5c6169b 100644 --- a/src/blackmisc/pqstring.h +++ b/src/blackmisc/pqstring.h @@ -42,13 +42,25 @@ namespace BlackMisc virtual bool isA(int metaTypeId) const override; public: + //! Number separators / group separators + enum SeparatorMode + { + SeparatorsCLocale, //!< 100,000.00 + SeparatorsLocale, //!< depending on QLocale, e.g. 100.000,00 in Germany + SeparatorsBestGuess //!< try to figure out + }; + + //! Group and digit separator + enum SeparatorIndex + { + Group, + Digit + }; + //! Default constructor CPqString() {} - /*! - * Constructor - * \param value such as 10km/h - */ + //! Constructor, for values such as 10km/h CPqString(const QString &value) : m_string(value) {} //! \copydoc CValueObject::toQVariant @@ -73,15 +85,15 @@ namespace BlackMisc static void registerMetadata(); //! Parse a string value like "100m", "10.3Mhz" - static QVariant parseToVariant(const QString &value); + static QVariant parseToVariant(const QString &value, SeparatorMode mode = SeparatorsCLocale); //! Parse into concrete type - template static PQ parse(const QString &value) + template static PQ parse(const QString &value, SeparatorMode mode = SeparatorsCLocale) { PQ invalid; invalid.setNull(); if (value.isEmpty()) return invalid; - QVariant qv = CPqString::parseToVariant(value); + QVariant qv = CPqString::parseToVariant(value, mode); if (!qv.isNull() && qv.canConvert()) { return qv.value(); diff --git a/src/blackmisc/pqtime.cpp b/src/blackmisc/pqtime.cpp index f9ef0592d..afc95730b 100644 --- a/src/blackmisc/pqtime.cpp +++ b/src/blackmisc/pqtime.cpp @@ -4,12 +4,26 @@ namespace BlackMisc { namespace PhysicalQuantities { + CTime::CTime(int hours, int minutes, int seconds) : CPhysicalQuantity(0, CTimeUnit::nullUnit()) + { + double value = hours + minutes / 100.0 + seconds / 10000.0; + if (minutes == 0 && seconds == 0) + { + (*this) = CTime(hours, CTimeUnit::h()); + } + else + { + if (seconds == 0) + (*this) = CTime(value, CTimeUnit::hrmin()); + else + (*this) = CTime(value, CTimeUnit::hms()); + } + } + CTime::CTime(const QTime &time) : CPhysicalQuantity(0, CTimeUnit::nullUnit()) { - int seconds = QTime(0, 0, 0).secsTo(time); - CTime converted(seconds, CTimeUnit::s()); - converted.switchUnit(CTimeUnit::hms()); - *this = converted; + CTime converted(time.hour(), time.minute(), time.second()); + (*this) = converted; } void CTime::parseFromString(const QString &time) @@ -22,12 +36,7 @@ namespace BlackMisc t = QTime::fromString(ts, "hh:mm"); else if (ts.length() == 8) t = QTime::fromString(ts, "hh:mm:ss"); - CTime parsed(t); - if (ts.length() == 5) - parsed.switchUnit(CTimeUnit::hrmin()); - else if (ts.length() == 8) - parsed.switchUnit(CTimeUnit::hms()); - *this = parsed; + (*this) = CTime(t); } else CPhysicalQuantity::parseFromString(ts); @@ -37,9 +46,19 @@ namespace BlackMisc { CTime copy(*this); copy.setUnit(CTimeUnit::hms()); - QString s = copy.toQString(false); - QTime t = QTime::fromString(s, "hh:mm:ss"); + QString s = copy.toQString(false).replace('h', ':').replace('m', ':').replace('s', ""); + QTime t = s.length() == 8 ? + QTime::fromString(s, "hh:mm:ss") : + QTime::fromString(s, "hh:mm"); return t; } + + QList CTime::getHrsMinSecParts() const + { + QTime t = this->toQTime(); + QList parts; + parts << t.hour() << t.minute() << t.second(); + return parts; + } } } diff --git a/src/blackmisc/pqtime.h b/src/blackmisc/pqtime.h index 17e873c57..11b913227 100644 --- a/src/blackmisc/pqtime.h +++ b/src/blackmisc/pqtime.h @@ -19,12 +19,24 @@ namespace BlackMisc class CTime : public CPhysicalQuantity { public: + + //! Parts + enum Parts + { + Hours = 0, + Minutes, + Seconds + }; + //! Default constructor CTime() : CPhysicalQuantity(0, CTimeUnit::defaultUnit()) {} //! Init by double value CTime(double value, const CTimeUnit &unit) : CPhysicalQuantity(value, unit) {} + //! By hours, minutes, seconds + CTime(int hours, int minutes, int seconds = 0); + //! By Qt time CTime(const QTime &time); @@ -43,6 +55,9 @@ namespace BlackMisc //! To Qt time QTime toQTime() const; + //! Parts hh, mm, ss + QList getHrsMinSecParts() const; + }; } // namespace diff --git a/src/blackmisc/pqunits.cpp b/src/blackmisc/pqunits.cpp index ed7202835..5ea01e73e 100644 --- a/src/blackmisc/pqunits.cpp +++ b/src/blackmisc/pqunits.cpp @@ -62,7 +62,7 @@ namespace BlackMisc double se = CMath::trunc((value - hr - mi / 100.0) * 1000000) / 100.0; const char *fmt = value < 0 ? "-%L1h%L2m%L3s" : "%L1h%L2m%L3s"; s = i18n ? QCoreApplication::translate("CMeasurementUnit", fmt) : fmt; - s = s.arg(fabs(hr), 0, 'f', 0).arg(fabs(mi), 2, 'f', 0, '0').arg(fabs(se), 2, 'f', digits, '0'); + s = s.arg(fabs(hr), 2, 'f', 0, '0').arg(fabs(mi), 2, 'f', 0, '0').arg(fabs(se), 2, 'f', digits, '0'); } else if ((*this) == CTimeUnit::hrmin()) { @@ -72,7 +72,7 @@ namespace BlackMisc double mi = CMath::trunc((value - hr) * 100.0); const char *fmt = value < 0 ? "-%L1h%L2m" : "%L1h%L2m"; s = i18n ? QCoreApplication::translate("CMeasurementUnit", fmt) : fmt; - s = s.arg(fabs(hr), 0, 'f', 0).arg(fabs(mi), 2, 'f', digits, '0'); + s = s.arg(fabs(hr), 2, 'f', 0, '0').arg(fabs(mi), 2, 'f', digits, '0'); } else if ((*this) == CTimeUnit::minsec()) { @@ -82,7 +82,7 @@ namespace BlackMisc double se = CMath::trunc((value - mi) * 100.0); const char *fmt = value < 0 ? "-%L2m%L3s" : "%L2m%L3s"; s = i18n ? QCoreApplication::translate("CMeasurementUnit", fmt) : fmt; - s = s.arg(fabs(mi), 0, 'f', 0).arg(fabs(se), 2, 'f', digits, '0'); + s = s.arg(fabs(mi), 2, 'f', 0, '0').arg(fabs(se), 2, 'f', digits, '0'); } else {