diff --git a/src/blackmisc/avaircraft.cpp b/src/blackmisc/avaircraft.cpp index c55ca97dd..d3d37ff96 100644 --- a/src/blackmisc/avaircraft.cpp +++ b/src/blackmisc/avaircraft.cpp @@ -20,11 +20,13 @@ namespace BlackMisc namespace Aviation { CAircraft::CAircraft(const CCallsign &callsign, const Network::CUser &user, const CAircraftSituation &situation) - : m_callsign(callsign), m_pilot(user), m_situation(situation), m_distanceToPlane(0, BlackMisc::PhysicalQuantities::CLengthUnit::nullUnit()) + : m_callsign(callsign), m_pilot(user), m_situation(situation) { // sync callsigns if (!this->m_pilot.hasValidCallsign() && !callsign.isEmpty()) + { this->m_pilot.setCallsign(callsign); + } } /* @@ -201,6 +203,5 @@ namespace BlackMisc } } - } // namespace } // namespace diff --git a/src/blackmisc/avaircraft.h b/src/blackmisc/avaircraft.h index 2df7956ae..f8cccdaf6 100644 --- a/src/blackmisc/avaircraft.h +++ b/src/blackmisc/avaircraft.h @@ -28,9 +28,7 @@ namespace BlackMisc { namespace Aviation { - /*! - * Value object encapsulating information of an aircraft - */ + //! Value object encapsulating information of an aircraft class CAircraft : public CValueObjectStdTuple, public Geo::ICoordinateGeodetic { public: @@ -48,7 +46,7 @@ namespace BlackMisc }; //! Default constructor. - CAircraft() : m_distanceToPlane(0, BlackMisc::PhysicalQuantities::CLengthUnit::nullUnit()) {} + CAircraft() {} //! Constructor. CAircraft(const CCallsign &callsign, const BlackMisc::Network::CUser &user, const CAircraftSituation &situation); @@ -63,7 +61,7 @@ namespace BlackMisc QString getCallsignAsString() const { return m_callsign.asString(); } //! Set callsign - void setCallsign(const CCallsign &callsign) { this->m_callsign = callsign; this->m_pilot.setCallsign(callsign); } + virtual void setCallsign(const CCallsign &callsign) { this->m_callsign = callsign; this->m_pilot.setCallsign(callsign); } //! Get situation. const CAircraftSituation &getSituation() const { return m_situation; } @@ -80,14 +78,14 @@ namespace BlackMisc //! Get user's real id QString getPilotId() { return m_pilot.getId(); } - //! Set user - void setPilot(const BlackMisc::Network::CUser &user) { m_pilot = user; this->m_pilot.setCallsign(this->m_callsign);} + //! Set pilot (user) + virtual void setPilot(const BlackMisc::Network::CUser &user) { m_pilot = user; this->m_pilot.setCallsign(this->m_callsign);} //! Get ICAO info const CAircraftIcao &getIcaoInfo() const { return m_icao; } //! Set ICAO info - void setIcaoInfo(const CAircraftIcao &icao) { m_icao = icao; } + virtual void setIcaoInfo(const CAircraftIcao &icao) { m_icao = icao; } //! Get the distance to own plane const BlackMisc::PhysicalQuantities::CLength &getDistanceToPlane() const { return m_distanceToPlane; } @@ -104,9 +102,15 @@ namespace BlackMisc //! Has valid id? bool hasValidId() const { return this->m_pilot.hasValidId(); } + //! Valid designator? + bool hasValidAircraftDesignator() const { return this->m_icao.hasAircraftDesignator(); } + //! Valid designators? bool hasValidAircraftAndAirlineDesignator() const { return this->m_icao.hasAircraftAndAirlineDesignator(); } + //! Valid callsign + bool hasValidCallsign() const { return CCallsign::isValidCallsign(this->getCallsign().asString()); } + //! Distance to aircraft PhysicalQuantities::CLength calculcateDistanceToPosition(const Geo::CCoordinateGeodetic &position) const; @@ -241,15 +245,15 @@ namespace BlackMisc private: BLACK_ENABLE_TUPLE_CONVERSION(CAircraft) - CCallsign m_callsign; + CCallsign m_callsign; BlackMisc::Network::CUser m_pilot; - CAircraftSituation m_situation; - BlackMisc::Aviation::CComSystem m_com1system; - BlackMisc::Aviation::CComSystem m_com2system; - BlackMisc::Aviation::CTransponder m_transponder; - BlackMisc::Aviation::CSelcal m_selcal; - CAircraftIcao m_icao; - BlackMisc::PhysicalQuantities::CLength m_distanceToPlane; + CAircraftSituation m_situation; + CComSystem m_com1system; + CComSystem m_com2system; + CTransponder m_transponder; + CSelcal m_selcal; + CAircraftIcao m_icao; + BlackMisc::PhysicalQuantities::CLength m_distanceToPlane {0, BlackMisc::PhysicalQuantities::CLengthUnit::nullUnit()}; }; } // namespace } // namespace diff --git a/src/blackmisc/avaircrafticao.cpp b/src/blackmisc/avaircrafticao.cpp index b70000f4b..22cfd5008 100644 --- a/src/blackmisc/avaircrafticao.cpp +++ b/src/blackmisc/avaircrafticao.cpp @@ -19,11 +19,9 @@ namespace BlackMisc { namespace Aviation { - /* - * Convert to string - */ - QString CAircraftIcao::convertToQString(bool /** i18n **/) const + QString CAircraftIcao::convertToQString(bool i18n) const { + Q_UNUSED(i18n); QString s(this->m_aircraftDesignator); if (this->hasAircraftCombinedType()) s.append(" ").append(this->m_aircraftCombinedType); if (this->hasAirlineDesignator()) s.append(" ").append(this->m_airlineDesignator); @@ -32,12 +30,19 @@ namespace BlackMisc return s; } - /* - * As string - */ + bool CAircraftIcao::hasAircraftDesignator() const + { + return !this->m_aircraftDesignator.isEmpty(); + } + + bool CAircraftIcao::hasKnownAircraftDesignator() const + { + return (this->getAircraftDesignator() != "ZZZZ"); + } + QString CAircraftIcao::asString() const { - if (this->m_aircraftDesignator.isEmpty()) return ""; + if (this->m_aircraftDesignator.isEmpty()) { return ""; } QString s(this->m_aircraftDesignator); if (!this->m_airlineDesignator.isEmpty()) { @@ -72,9 +77,6 @@ namespace BlackMisc return true; } - /* - * Property by index - */ CVariant CAircraftIcao::propertyByIndex(const BlackMisc::CPropertyIndex &index) const { if (index.isMyself()) { return this->toCVariant(); } @@ -96,9 +98,6 @@ namespace BlackMisc } } - /* - * Property by index - */ void CAircraftIcao::setPropertyByIndex(const CVariant &variant, const BlackMisc::CPropertyIndex &index) { if (index.isMyself()) @@ -128,19 +127,13 @@ namespace BlackMisc } } - /* - * Valid designator? - */ bool CAircraftIcao::isValidDesignator(const QString &designator) { static QRegularExpression regexp("^[A-Z]+[A-Z0-9]*$"); - if (designator.length() < 2 || designator.length() > 5) return false; + if (designator.length() < 2 || designator.length() > 5) { return false; } return (regexp.match(designator).hasMatch()); } - /* - * Valid combined type - */ bool CAircraftIcao::isValidCombinedType(const QString &combinedType) { static QRegularExpression regexp("^[A-Z][0-9][A-Z]$"); @@ -148,9 +141,6 @@ namespace BlackMisc return (regexp.match(combinedType).hasMatch()); } - /* - * Valid airline designator - */ bool CAircraftIcao::isValidAirlineDesignator(const QString &airline) { static QRegularExpression regexp("^[A-Z]+[A-Z0-9]*$"); diff --git a/src/blackmisc/avaircrafticao.h b/src/blackmisc/avaircrafticao.h index 945913386..a82e08ce2 100644 --- a/src/blackmisc/avaircrafticao.h +++ b/src/blackmisc/avaircrafticao.h @@ -69,7 +69,10 @@ namespace BlackMisc void setAircraftDesignator(const QString &icaoDesignator) { this->m_aircraftDesignator = icaoDesignator.trimmed().toUpper(); } //! Aircraft designator? - bool hasAircraftDesignator() const { return !this->m_aircraftDesignator.isEmpty(); } + bool hasAircraftDesignator() const; + + //! Has designator and designator is not "ZZZZ" + bool hasKnownAircraftDesignator() const; //! Get airline, e.g. "DLH" const QString &getAirlineDesignator() const { return this->m_airlineDesignator; } diff --git a/src/blackmisc/avcallsign.cpp b/src/blackmisc/avcallsign.cpp index b5a6d2df9..a45dd8d09 100644 --- a/src/blackmisc/avcallsign.cpp +++ b/src/blackmisc/avcallsign.cpp @@ -29,7 +29,8 @@ namespace BlackMisc QString CCallsign::unifyCallsign(const QString &callsign) { QString unified = callsign.toUpper(); - unified = unified.remove(QRegExp("[^a-zA-Z\\d\\s]")); + // allow A-Z, 0-9, _, but no spaces + unified = unified.remove(QRegExp("[^A-Z\\d_]")); return unified; } @@ -48,7 +49,7 @@ namespace BlackMisc if ("DEL" == t) { return CIconList::iconByIndex(CIcons::NetworkRoleDelivery); } if ("CTR" == t) { return CIconList::iconByIndex(CIcons::NetworkRoleCenter); } if ("SUP" == t) { return CIconList::iconByIndex(CIcons::NetworkRoleSup); } - if ("OBS" == t) { return CIconList::iconByIndex(CIcons::NetworkRoleApproach); } + if ("OBS" == t) { return CIconList::iconByIndex(CIcons::NetworkRoleObs); } if ("ATIS" == t) { return CIconList::iconByIndex(CIcons::AviationAtis); } return CIconList::iconByIndex(CIcons::NetworkRoleUnknown); } @@ -63,11 +64,17 @@ namespace BlackMisc */ bool CCallsign::isAtcCallsign() const { - if (this->hasSuffix()) - { - return atcCallsignSuffixes().contains(this->getSuffix(), Qt::CaseInsensitive); - } - return false; + if (!this->hasSuffix()) { return false; } + return atcCallsignSuffixes().contains(this->getSuffix(), Qt::CaseInsensitive); + } + + /* + * ATC callsign? + */ + bool CCallsign::isAtcAlikeCallsign() const + { + if (!this->hasSuffix()) { return false; } + return atcAlikeCallsignSuffixes().contains(this->getSuffix(), Qt::CaseInsensitive); } /* @@ -127,6 +134,8 @@ namespace BlackMisc return CVariant(this->getStringAsSet()); case IndexTelephonyDesignator: return CVariant(this->getTelephonyDesignator()); + case IndexSuffix: + return CVariant(this->getSuffix()); default: return CValueObject::propertyByIndex(index); } @@ -164,8 +173,10 @@ namespace BlackMisc */ bool CCallsign::isValidCallsign(const QString &callsign) { - static QRegularExpression regexp("^[A-Z]+[A-Z0-9]*$"); - if (callsign.length() < 2 || callsign.length() > 10) return false; + //! \todo sometimes callsigns such as 12345, really correct? + // static QRegularExpression regexp("^[A-Z]+[A-Z0-9]*$"); + static QRegularExpression regexp("^[A-Z0-9]*$"); + if (callsign.length() < 2 || callsign.length() > 10) { return false; } return (regexp.match(callsign).hasMatch()); } @@ -174,7 +185,13 @@ namespace BlackMisc */ const QStringList &CCallsign::atcCallsignSuffixes() { - static const QStringList a( { "ATIS", "APP", "GND", "TWR", "DEL", "CTR", "SUP", "FSS" }); + static const QStringList a( { "APP", "GND", "TWR", "DEL", "CTR" }); + return a; + } + + const QStringList &CCallsign::atcAlikeCallsignSuffixes() + { + static const QStringList a( { "ATIS", "APP", "GND", "OBS", "TWR", "DEL", "CTR", "SUP", "FSS" }); return a; } diff --git a/src/blackmisc/avcallsign.h b/src/blackmisc/avcallsign.h index da14867dd..9fb22335e 100644 --- a/src/blackmisc/avcallsign.h +++ b/src/blackmisc/avcallsign.h @@ -29,7 +29,8 @@ namespace BlackMisc { IndexCallsignString = BlackMisc::CPropertyIndex::GlobalIndexCCallsign, IndexCallsignStringAsSet, - IndexTelephonyDesignator + IndexTelephonyDesignator, + IndexSuffix }; //! Default constructor. @@ -49,8 +50,13 @@ namespace BlackMisc bool isEmpty() const { return this->m_callsignAsSet.isEmpty(); } //! ATC callsign + //! \sa atcCallsignSuffixes() bool isAtcCallsign() const; + //! ATC alike callsign + //! \sa atcAlikeCallsignSuffixes() + bool isAtcAlikeCallsign() const; + //! Get callsign. const QString &asString() const { return this->m_callsign; } @@ -87,9 +93,12 @@ namespace BlackMisc //! Valid callsign? static bool isValidCallsign(const QString &callsign); - //! List of ATC suffixes (e.g. TWR); + //! List of real ATC suffixes (e.g. TWR); static const QStringList &atcCallsignSuffixes(); + //! List of real ("TWR") and treated like ATC suffixes (e.g. OBS); + static const QStringList &atcAlikeCallsignSuffixes(); + protected: //! \copydoc CValueObject::convertToQString() virtual QString convertToQString(bool i18n = false) const override; @@ -110,10 +119,10 @@ namespace BlackMisc } // namespace BLACK_DECLARE_TUPLE_CONVERSION(BlackMisc::Aviation::CCallsign, ( - attr(o.m_callsign, flags()), - attr(o.m_callsignAsSet, flags()), - attr(o.m_telephonyDesignator, flags()) -)) + attr(o.m_callsign, flags()), + attr(o.m_callsignAsSet, flags()), + attr(o.m_telephonyDesignator, flags()) + )) Q_DECLARE_METATYPE(BlackMisc::Aviation::CCallsign) #endif // guard diff --git a/src/blackmisc/aviocomsystem.h b/src/blackmisc/aviocomsystem.h index d4297e3f6..4fe286b64 100644 --- a/src/blackmisc/aviocomsystem.h +++ b/src/blackmisc/aviocomsystem.h @@ -51,11 +51,11 @@ namespace BlackMisc }; //! Default constructor - CComSystem() : m_channelSpacing(ChannelSpacing25KHz) {} + CComSystem() {} //! Constructor CComSystem(const QString &name, const BlackMisc::PhysicalQuantities::CFrequency &activeFrequency, const BlackMisc::PhysicalQuantities::CFrequency &standbyFrequency = CModulator::FrequencyNotSet()): - CValueObjectStdTuple(name, activeFrequency, standbyFrequency == CModulator::FrequencyNotSet() ? activeFrequency : standbyFrequency), m_channelSpacing(ChannelSpacing25KHz) + CValueObjectStdTuple(name, activeFrequency, standbyFrequency == CModulator::FrequencyNotSet() ? activeFrequency : standbyFrequency) { } //! Set active frequency @@ -172,7 +172,7 @@ namespace BlackMisc virtual bool validValues() const override; private: - ChannelSpacing m_channelSpacing; //!< channel spacing + ChannelSpacing m_channelSpacing = ChannelSpacing25KHz; //!< channel spacing /*! * Give me channel spacing in KHz diff --git a/src/blackmisc/nwclient.cpp b/src/blackmisc/nwclient.cpp index 0fd224290..52bda23fb 100644 --- a/src/blackmisc/nwclient.cpp +++ b/src/blackmisc/nwclient.cpp @@ -67,9 +67,18 @@ namespace BlackMisc bool CClient::hasCapability(CClient::Capabilities capability) const { if (this->m_capabilities.contains(capability)) + { return this->m_capabilities.value(capability).toBool(); + } else + { return false; + } + } + + void CClient::setUserCallsign(const Aviation::CCallsign &callsign) + { + this->m_user.setCallsign(callsign); } /* diff --git a/src/blackmisc/nwclient.h b/src/blackmisc/nwclient.h index 597865fb6..6a9e4c3b1 100644 --- a/src/blackmisc/nwclient.h +++ b/src/blackmisc/nwclient.h @@ -13,7 +13,7 @@ #define BLACKMISC_CLIENT_H #include "nwuser.h" -#include "nwaircraftmodel.h" +#include "blackmisc/simulation/aircraftmodel.h" #include "nwvoicecapabilities.h" #include "propertyindex.h" #include "propertyindexvariantmap.h" @@ -64,7 +64,7 @@ namespace BlackMisc const BlackMisc::Aviation::CCallsign &getCallsign() const { return this->m_user.getCallsign(); } //! ATC client - bool isAtc() const { return getCallsign().isAtcCallsign(); } + bool isAtc() const { return getCallsign().isAtcAlikeCallsign(); } //! Get capabilities CPropertyIndexVariantMap getCapabilities() const { return this->m_capabilities; } @@ -99,6 +99,9 @@ namespace BlackMisc //! User void setUser(const CUser &user) { this->m_user = user;} + //! User's callsign + void setUserCallsign(const BlackMisc::Aviation::CCallsign &callsign); + //! Server const QString &getServer() const { return this->m_server; } @@ -106,10 +109,13 @@ namespace BlackMisc void setServer(const QString &server) { this->m_server = server;} //! Model - const CAircraftModel &getAircraftModel() const { return this->m_model; } + const BlackMisc::Simulation::CAircraftModel &getAircraftModel() const { return this->m_model; } + + //! \copydoc CAircraftModel::hasQueriedModelString + bool hasQueriedModelString() const { return this->m_model.hasQueriedModelString(); } //! Set model - void setAircraftModel(const CAircraftModel &model) { this->m_model = model; } + void setAircraftModel(const BlackMisc::Simulation::CAircraftModel &model) { this->m_model = model; } //! \copydoc CValueObject::toIcon() virtual CIcon toIcon() const override { return this->m_user.toIcon(); } @@ -127,7 +133,7 @@ namespace BlackMisc private: BLACK_ENABLE_TUPLE_CONVERSION(CClient) CUser m_user; - CAircraftModel m_model; + BlackMisc::Simulation::CAircraftModel m_model; CPropertyIndexVariantMap m_capabilities; QString m_server; CVoiceCapabilities m_voiceCapabilities; diff --git a/src/blackmisc/nwuser.cpp b/src/blackmisc/nwuser.cpp index 514df5bd9..1c9b58bfa 100644 --- a/src/blackmisc/nwuser.cpp +++ b/src/blackmisc/nwuser.cpp @@ -8,18 +8,35 @@ */ #include "nwuser.h" +#include "blackmisc/avairporticao.h" #include "blackmisc/icon.h" #include "blackmisc/blackmiscfreefunctions.h" #include "blackmisc/propertyindex.h" #include "blackmisc/variant.h" #include +#include + +using namespace BlackMisc::Aviation; namespace BlackMisc { namespace Network { - QString CUser::convertToQString(bool /** i18n **/) const + CUser::CUser(const QString &id, const QString &realname, const CCallsign &callsign) + : m_id(id.trimmed()), m_realname(realname), m_callsign(callsign) { + this->setRealName(realname); // extracts homebase + } + + CUser::CUser(const QString &id, const QString &realname, const QString &email, const QString &password, const CCallsign &callsign) + : m_id(id.trimmed()), m_realname(realname), m_email(email), m_password(password), m_callsign(callsign) + { + this->setRealName(realname); // extracts homebase + } + + QString CUser::convertToQString(bool i18n) const + { + Q_UNUSED(i18n); if (this->m_realname.isEmpty()) return ""; QString s = this->m_realname; if (this->hasValidId()) @@ -33,6 +50,33 @@ namespace BlackMisc return s; } + void CUser::setRealName(const QString &realname) + { + // try to strip homebase + // I understand the limitations, but we will have more correct hits as failures I assume + const QRegularExpression reg("(-\\s*|\\s)([A-Z]{4})$"); + QString rn = realname.trimmed().simplified(); + if (rn.isEmpty()) + { + this->m_realname = ""; + return; + } + + if (!this->hasValidHomebase()) + { + //! only apply stripping if home base is not explicitly given + QRegularExpressionMatch match = reg.match(rn); + if (match.hasMatch()) + { + int pos = match.capturedStart(0); + QString icao = match.captured(0).trimmed().right(4); + rn = rn.left(pos).trimmed(); + this->setHomebase(CAirportIcao(icao)); + } + } + this->m_realname = rn; + } + CStatusMessageList CUser::validate() const { CStatusMessageList msgs; @@ -48,27 +92,43 @@ namespace BlackMisc */ void CUser::syncronizeData(CUser &otherUser) { - if (otherUser == (*this)) return; + if (otherUser == (*this)) { return; } if (this->hasValidRealName()) + { otherUser.setRealName(this->getRealName()); + } else if (otherUser.hasValidRealName()) + { this->setRealName(otherUser.getRealName()); + } if (this->hasValidId()) + { otherUser.setId(this->getId()); + } else if (otherUser.hasValidId()) + { this->setId(otherUser.getId()); + } if (this->hasValidEmail()) + { otherUser.setEmail(this->getEmail()); + } else if (otherUser.hasValidEmail()) + { this->setEmail(otherUser.getEmail()); + } if (this->hasValidCallsign()) + { otherUser.setCallsign(this->getCallsign()); + } else if (otherUser.hasValidCallsign()) + { this->setCallsign(otherUser.getCallsign()); + } } bool CUser::isValidVatsimId(const QString &id) @@ -97,6 +157,8 @@ namespace BlackMisc return CVariant(this->m_password); case IndexRealName: return CVariant(this->m_realname); + case IndexHomebase: + return this->m_homebase.propertyByIndex(index.copyFrontRemoved()); case IndexCallsign: return this->m_callsign.propertyByIndex(index.copyFrontRemoved()); default: @@ -129,6 +191,9 @@ namespace BlackMisc case IndexRealName: this->setRealName(variant.value()); break; + case IndexHomebase: + this->m_homebase.setPropertyByIndex(variant, index.copyFrontRemoved()); + break; case IndexCallsign: this->m_callsign.setPropertyByIndex(variant, index.copyFrontRemoved()); break; diff --git a/src/blackmisc/nwuser.h b/src/blackmisc/nwuser.h index 0cbcc8c25..4d809891a 100644 --- a/src/blackmisc/nwuser.h +++ b/src/blackmisc/nwuser.h @@ -38,7 +38,8 @@ namespace BlackMisc IndexId, IndexPassword, IndexRealName, - IndexCallsign + IndexCallsign, + IndexHomebase }; //! Default constructor. @@ -48,20 +49,16 @@ namespace BlackMisc CUser(const BlackMisc::Aviation::CCallsign &callsign) : m_callsign(callsign) {} //! Constructor. - CUser(const QString &id, const QString &realname, const BlackMisc::Aviation::CCallsign &callsign) - : m_id(id), m_realname(realname), m_callsign(callsign) - {} + CUser(const QString &id, const QString &realname, const BlackMisc::Aviation::CCallsign &callsign); //! Constructor. - CUser(const QString &id, const QString &realname, const QString &email = "", const QString &password = "", const BlackMisc::Aviation::CCallsign &callsign = BlackMisc::Aviation::CCallsign()) - : m_id(id), m_realname(realname), m_email(email), m_password(password), m_callsign(callsign) - {} + CUser(const QString &id, const QString &realname, const QString &email = "", const QString &password = "", const BlackMisc::Aviation::CCallsign &callsign = BlackMisc::Aviation::CCallsign()); //! Get full name. QString getRealName() const { return m_realname; } //! setRealName - void setRealName(const QString &realname) { m_realname = realname.trimmed().simplified(); } + void setRealName(const QString &realname); //! Get password QString getPassword() const { return m_password; } @@ -84,6 +81,9 @@ namespace BlackMisc //! Has associated callsign? bool hasValidCallsign() const { return !m_callsign.isEmpty(); } + //! Valid homebase + bool hasValidHomebase() const { return !m_homebase.isEmpty(); } + //! Validate, provide details about issues BlackMisc::CStatusMessageList validate() const; @@ -138,6 +138,7 @@ namespace BlackMisc private: BLACK_ENABLE_TUPLE_CONVERSION(CUser) + QString m_id; QString m_realname; QString m_email;