6 #include <QRegularExpression>
7 #include <QRegularExpressionMatch>
18 namespace swift::misc::aviation
21 : m_callsignAsSet(callsign.trimmed()), m_callsign(
CCallsign::unifyCallsign(callsign, hint)), m_typeHint(hint)
25 : m_callsignAsSet(callsign.trimmed()), m_callsign(
CCallsign::unifyCallsign(callsign, hint)),
26 m_telephonyDesignator(telephonyDesignator.trimmed()), m_typeHint(hint)
30 : m_callsignAsSet(callsign), m_callsign(
CCallsign::unifyCallsign(callsign, hint)), m_typeHint(hint)
36 qRegisterMetaType<CCallsign::TypeHint>();
49 if (QStringView(u
"FSS") == suffix) {
return 1; }
50 if (QStringView(u
"CTR") == suffix) {
return 2; }
51 if (QStringView(u
"APP") == suffix) {
return 3; }
52 if (QStringView(u
"DEP") == suffix) {
return 4; }
53 if (QStringView(u
"TWR") == suffix) {
return 5; }
54 if (QStringView(u
"GND") == suffix) {
return 6; }
55 if (QStringView(u
"DEL") == suffix) {
return 7; }
56 if (QStringView(u
"ATIS") == suffix) {
return 8; }
57 if (QStringView(u
"SUP") == suffix) {
return 9; }
58 if (QStringView(u
"OBS") == suffix) {
return 10; }
59 if (QStringView(u
"INS") == suffix) {
return 11; }
60 if (QStringView(u
"ADM") == suffix) {
return 12; }
61 if (QStringView(u
"VATGOV") == suffix) {
return 13; }
62 if (QStringView(u
"VATSIM") == suffix) {
return 14; }
63 if (QStringView(u
"EXAM") == suffix) {
return 15; }
64 return std::numeric_limits<int>::max();
69 const QString ucCallsign = callsign.trimmed().toUpper();
75 case Atc:
return removeChars(ucCallsign, [](QChar c) {
return !c.isLetterOrNumber() && c !=
'_' && c !=
'-'; });
76 case Aircraft:
return removeChars(ucCallsign, [](QChar c) {
return !c.isLetterOrNumber() && c !=
'_'; });
83 return removeChars(ucCallsign, [](QChar c) {
return !c.isLetterOrNumber() && c !=
'_' && c !=
'-'; });
87 return removeChars(ucCallsign, [](QChar c) {
return !c.isLetterOrNumber() && c !=
'_'; });
92 if (callsign.m_callsign.startsWith(QStringView(u
"VATGOV")))
105 callsign.
isEmpty() ? message.trimmed() :
106 callsign.
toQString() +
": " + message.trimmed());
113 if (!log) {
return; }
114 if (message.isEmpty()) {
return; }
121 const QString sfx = suffix.toUpper();
122 if (QStringView(u
"APP") == sfx) {
return CIcon::iconByIndex(CIcons::NetworkRoleApproach); }
123 if (QStringView(u
"DEP") == sfx) {
return CIcon::iconByIndex(CIcons::NetworkRoleDeparture); }
124 if (QStringView(u
"GND") == sfx) {
return CIcon::iconByIndex(CIcons::NetworkRoleGround); }
125 if (QStringView(u
"TWR") == sfx) {
return CIcon::iconByIndex(CIcons::NetworkRoleTower); }
126 if (QStringView(u
"DEL") == sfx) {
return CIcon::iconByIndex(CIcons::NetworkRoleDelivery); }
127 if (QStringView(u
"CTR") == sfx) {
return CIcon::iconByIndex(CIcons::NetworkRoleCenter); }
128 if (QStringView(u
"SUP") == sfx) {
return CIcon::iconByIndex(CIcons::NetworkRoleSup); }
129 if (QStringView(u
"OBS") == sfx) {
return CIcon::iconByIndex(CIcons::NetworkRoleObs); }
131 if (QStringView(u
"FSS") == sfx) {
return CIcon::iconByIndex(CIcons::NetworkRoleFss); }
134 if (QStringView(u
"VATSIM") == sfx) {
return CIcon::iconByIndex(CIcons::NetworkRoleSup); }
135 if (QStringView(u
"VATGOV") == sfx) {
return CIcon::iconByIndex(CIcons::NetworkRoleSup); }
142 if (!this->
hasSuffix()) {
return false; }
148 if (this->
getTypeHint() == Aircraft) {
return false; }
149 return m_callsign.endsWith(
"SUP");
154 return m_callsignAsSet ==
"*" || m_callsign ==
"*" || m_callsignAsSet ==
"BROADCAST";
159 m_callsignAsSet =
"BROADCAST";
160 m_callsign =
"BROADCAST";
165 m_callsignAsSet =
"SUP";
171 return m_callsign.startsWith(pilotCallsign.
asString()) &&
172 m_callsign.size() == pilotCallsign.
asString().size() + 1 &&
173 m_callsign.at(m_callsign.size() - 1) >=
'A' && m_callsign.at(m_callsign.size() - 1) <=
'Z';
179 if (m_callsignAsSet.startsWith(
'*')) {
return this->
getStringAsSet(); }
189 if (m_callsign.length() >= 4) {
return m_callsign.left(4).toUpper(); }
196 if (this->
getTypeHint() == Aircraft) {
return false; }
197 if (!this->
hasSuffix()) {
return false; }
205 if (this->
isEmpty()) {
return {}; }
207 if (obs.endsWith(
"_OBS", Qt::CaseInsensitive)) {
return obs; }
208 if (obs.contains(
'_')) { obs = obs.left(obs.lastIndexOf(
'_')); }
209 return obs.append(
"_OBS").toUpper();
221 QString flightNumber;
227 QString identification;
236 flightNumber.clear();
237 if (m_callsign.length() < 3) {
return {}; }
240 thread_local
const QRegularExpression regExp(
"(^[A-Z]{3,})(\\d+)");
241 const QRegularExpressionMatch match = regExp.match(m_callsign);
242 if (!match.hasMatch()) {
return {}; }
244 const QString airline = match.captured(1);
245 flightNumber = match.captured(2);
248 if (airline.length() == 3)
250 flightIdentification = m_callsign.length() > 3 ? m_callsign.mid(3) : QString();
253 if (airline.length() == 4 && airline.startsWith(
'V'))
255 flightIdentification = m_callsign.length() > 4 ? m_callsign.mid(4) : QString();
260 if (flightNumber.length() >= 1 && airline.length() == 4)
262 flightIdentification = m_callsign.mid(3);
263 return airline.left(3);
272 QString flightNumber;
273 QString identification;
274 const QString airline = this->
getAirlinePrefix(flightNumber, identification);
275 return airline.isEmpty() ? QString() : identification;
281 QString flightNumber;
283 return airline.isEmpty() ? QString() : flightNumber;
307 return other == (*this);
312 if (index.
isMyself()) {
return QVariant::fromValue(*
this); }
316 case IndexCallsignString:
return QVariant(this->
asString());
317 case IndexCallsignStringAsSet:
return QVariant(this->
getStringAsSet());
319 case IndexSuffix:
return QVariant(this->
getSuffix());
334 case IndexCallsignString: m_callsign =
unifyCallsign(variant.toString());
break;
335 case IndexCallsignStringAsSet: m_callsignAsSet = variant.toString();
break;
336 case IndexTelephonyDesignator: m_telephonyDesignator = variant.toString();
break;
343 if (index.
isMyself()) {
return m_callsign.compare(compareValue.m_callsign, Qt::CaseInsensitive); }
347 case IndexCallsignString:
return m_callsign.compare(compareValue.m_callsign, Qt::CaseInsensitive);
348 case IndexCallsignStringAsSet:
349 return m_callsignAsSet.compare(compareValue.m_callsignAsSet, Qt::CaseInsensitive);
350 case IndexTelephonyDesignator:
351 return m_telephonyDesignator.compare(compareValue.m_telephonyDesignator, Qt::CaseInsensitive);
352 case IndexSuffix:
return this->
getSuffix().compare(compareValue.
getSuffix(), Qt::CaseInsensitive);
355 Q_ASSERT_X(
false, Q_FUNC_INFO,
"Compare failed");
365 default:
return !this->
isEmpty();
371 if (callsign.length() < 2 || callsign.length() > 10) {
return false; }
372 return !
containsChar(callsign, [](QChar c) {
return !c.isUpper() && !c.isDigit(); });
383 if (callsign.length() < 2 || callsign.length() > 10) {
return false; }
384 return !
containsChar(callsign, [](QChar c) {
return c !=
'-' && c !=
'_' && !c.isUpper() && !c.isDigit(); });
391 static const QStringList a({
"APP",
"GND",
"DEP",
"TWR",
"DEL",
"CTR" });
397 static const QStringList a({
"ATIS",
"APP",
"GND",
"OBS",
"DEP",
"TWR",
"DEL",
"CTR",
"SUP",
"FSS",
"INS" });
403 if (!callsign.contains(
"_")) {
return false; }
404 const QStringView uc = callsign.toUpper();
408 if (uc.endsWith(r)) {
return true; }
Value object for icons. An icon is stored in the global icon repository and identified by its index....
static const CIcon & iconByIndex(CIcons::IconIndex index)
Icon for given index.
static const QString & aviation()
Aviation specific.
A sequence of log categories.
static CLogCategoryList fromQStringList(const QStringList &stringList)
Convert a string list, such as that returned by toQStringList(), into a CLogCategoryList.
Non-owning reference to a CPropertyIndex with a subset of its features.
CastType frontCasted() const
First element casted to given type, usually the PropertIndex enum.
bool isMyself() const
Myself index, used with nesting.
void push_back(const T &value)
Appends an element at the end of the sequence.
Streamable status message, e.g.
Status messages, e.g. from Core -> GUI.
Value object encapsulating information of a callsign.
int getSuffixSortOrder() const
Sort order by suffix.
void clear()
Clear this callsign.
int comparePropertyByIndex(CPropertyIndexRef index, const CCallsign &compareValue) const
Compare for index.
const QString & asString() const
Get callsign (normalized)
bool isMaybeCopilotCallsign(const CCallsign &pilotCallsign) const
Returns true if this is a co-pilot callsign of pilot. The logic is that the callsign is the same as t...
static int suffixToSortOrder(const QString &suffix)
Index for ATC suffix, if unknown int max value.
QString getSuffix() const
Get the callsign suffix ("TWR", "ATIS" ...) if any ("_" is removed)
TypeHint
Representing what.
bool hasSuffix() const
Suffix such as "_TWR"?
void markAsBroadcastCallsign()
Set a human readable name as "broadcast" callsign.
QString convertToQString(bool i18n=false) const
Cast as QString.
int getFlightNumberInt() const
Flight number as integer.
QString getFlightIndentification() const
Flight number (e.g. DLH1234 -> 1234) if applicable.
static const QStringList & atcCallsignSuffixes()
List of real ATC suffixes (e.g. TWR);.
static bool looksLikeAtcCallsign(const QString &callsign)
Does this look like an ATC callsign.
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
void markAsWallopCallsign()
Set a human readable name as "wallop-channel" callsign.
QString getFlightNumber() const
Flight number (e.g. DLH1234 -> 1234) if applicable.
bool isSupervisorCallsign() const
Supervisor?
static void addLogDetailsToList(CStatusMessageList *log, const CCallsign &callsign, const QString &message, const QStringList &extraCategories={}, CStatusMessage::StatusSeverity s=CStatusMessage::SeverityInfo)
Specialized log for matching / reverse lookup.
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
bool isObserverCallsign() const
Observer callsign?
bool isAtcAlikeCallsign() const
ATC alike callsign.
static CStatusMessage logMessage(const CCallsign &callsign, const QString &message, const QStringList &extraCategories={}, CStatusMessage::StatusSeverity s=CStatusMessage::SeverityInfo)
Specialized log message for matching / reverse lookup.
static QString unifyCallsign(const QString &callsign, TypeHint hint=NoHint)
Unify the callsign by removing illegal characters.
bool isEmpty() const
Is empty?
static bool isValidAircraftCallsign(const QString &callsign)
Valid callsign?
const QString & getTelephonyDesignator() const
Get callsign telephony designator (how callsign is pronounced)
TypeHint getTypeHint() const
Type hint.
static const CIcon & convertToIcon(const CCallsign &callsign)
Representing icon.
QString getAsObserverCallsignString() const
Makes this callsign looking like an observer callsign (DAMBZ -> DAMBZ_OBS)
bool hasAtcSuffix() const
Has an ATC suffix?
CCallsign()
Default constructor.
QString getIcaoCode() const
Get ICAO code, if this makes sense (EDDF_TWR -> EDDF)
QString getAirlinePrefix() const
Airline suffix (e.g. DLH1234 -> DLH) if applicable.
static const CIcon & atcSuffixToIcon(const QString &suffix)
Suffix to icon.
bool isAtcCallsign() const
ATC callsign.
static void registerMetadata()
Register metadata.
QString getFsdCallsignString() const
The callsign string used with FSD.
bool isSameAsSet() const
Same as set callsign?
bool equalsString(const QString &callsignString) const
Equals callsign string?
bool isBroadcastCallsign() const
Pseudo callsing for broadcast messages.
const QString & getStringAsSet() const
Get callsign.
static bool isValidAtcCallsign(const QString &callsign)
Valid callsign?
bool isValid() const
Valid callsign?
static const QStringList & atcAlikeCallsignSuffixes()
List of real ("TWR") and treated like ATC suffixes (e.g. OBS);.
int comparePropertyByIndex(CPropertyIndexRef index, const Derived &compareValue) const
Compare for index.
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
QString toQString(bool i18n=false) const
Cast as QString.
QString removeChars(const QString &s, F predicate)
Return a string with characters removed that match the given predicate.
StatusSeverity
Status severities.
bool containsChar(const QString &s, F predicate)
True if any character in the string matches the given predicate.
#define SWIFT_DEFINE_VALUEOBJECT_MIXINS(Namespace, Class)
Explicit template definition of mixins for a CValueObject subclass.