mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-21 04:45:31 +08:00
refs #219, load flight plan
* fixed issue with parsing, only default locale is used. Now user's local possible * allow to load FP for other callsigns as well (voice capabilities) * Improved handling of CTime, inclusive bug fixes and time formatting * Max. lengths for FP fields as const value (so we can change it if required) * Load FP from GUI component * Samples for PQ classes * Adjusted depending classes (e.g. client)
This commit is contained in:
@@ -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<CLength>(v);
|
||||
CLength l = BlackMisc::PhysicalQuantities::CPqString::parse<CLength>(v, mode);
|
||||
*this = CAltitude(l, rd);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<PQ>(value);
|
||||
*this = CPqString::parse<PQ>(value, CPqString::SeparatorsCLocale);
|
||||
}
|
||||
|
||||
//! Register metadata of unit and quantity
|
||||
|
||||
@@ -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<CAccelerationUnit>(unit))
|
||||
|
||||
@@ -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 <class PQ> static PQ parse(const QString &value)
|
||||
template <class PQ> 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<PQ>())
|
||||
{
|
||||
return qv.value<PQ>();
|
||||
|
||||
@@ -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<int> CTime::getHrsMinSecParts() const
|
||||
{
|
||||
QTime t = this->toQTime();
|
||||
QList<int> parts;
|
||||
parts << t.hour() << t.minute() << t.second();
|
||||
return parts;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,12 +19,24 @@ namespace BlackMisc
|
||||
class CTime : public CPhysicalQuantity<CTimeUnit, CTime>
|
||||
{
|
||||
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<int> getHrsMinSecParts() const;
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user