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:
Klaus Basan
2014-06-05 02:33:03 +02:00
parent e823f87bab
commit 226edda23b
17 changed files with 293 additions and 147 deletions

View File

@@ -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);
}

View File

@@ -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();

View File

@@ -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

View File

@@ -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

View File

@@ -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))

View File

@@ -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>();

View File

@@ -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;
}
}
}

View File

@@ -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

View File

@@ -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
{