swift
distributor.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2015 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #include <QJsonValue>
7 #include <QStringBuilder>
8 #include <Qt>
9 #include <QtGlobal>
10 
11 #include "misc/logcategories.h"
12 #include "misc/statusmessage.h"
13 #include "misc/stringutils.h"
14 
15 SWIFT_DEFINE_VALUEOBJECT_MIXINS(swift::misc::simulation, CDistributor)
16 
17 namespace swift::misc::simulation
18 {
19  CDistributor::CDistributor(const QString &key) { this->setDbKey(unifyKeyOrAlias(key)); }
20 
21  CDistributor::CDistributor(const QString &id, const QString &description, const QString &alias1,
22  const QString &alias2, const CSimulatorInfo &simulator)
23  : m_description(description), m_alias1(alias1), m_alias2(alias2), m_simulator(simulator)
24  {
25  this->setDbKey(unifyKeyOrAlias(id));
26  }
27 
29  {
30  if (!this->getDbKey().isEmpty() && !this->getDescription().isEmpty())
31  {
32  return this->getDbKey() % u' ' % this->getDescription();
33  }
34  if (!this->getDbKey().isEmpty()) { return this->getDbKey(); }
35  return {};
36  }
37 
38  bool CDistributor::matchesKeyOrAlias(const QString &keyOrAlias) const
39  {
40  QString s(keyOrAlias.trimmed().toUpper());
41  if (s.isEmpty()) { return false; }
42  return (getDbKey() == s || getAlias1() == s || getAlias2() == s);
43  }
44 
45  bool CDistributor::matchesKeyOrAlias(const CDistributor &distributor) const
46  {
47  if (distributor.hasValidDbKey() && this->matchesKeyOrAlias(distributor.getDbKey())) { return true; }
48  if (distributor.hasAlias1() && this->matchesKeyOrAlias(distributor.getAlias1())) { return true; }
49  return (distributor.hasAlias2() && this->matchesKeyOrAlias(distributor.getAlias2()));
50  }
51 
52  bool CDistributor::matchesSimulator(const CSimulatorInfo &simulator) const
53  {
54  return m_simulator.matchesAny(simulator);
55  }
56 
58  {
59  if (index.isMyself()) { return QVariant::fromValue(*this); }
60  if (IDatastoreObjectWithStringKey::canHandleIndex(index))
61  {
62  return IDatastoreObjectWithStringKey::propertyByIndex(index);
63  }
64  if (IOrderable::canHandleIndex(index)) { return IOrderable::propertyByIndex(index); }
65 
66  const auto i = index.frontCasted<ColumnIndex>();
67  switch (i)
68  {
69  case IndexAlias1: return QVariant::fromValue(m_alias1);
70  case IndexAlias2: return QVariant::fromValue(m_alias2);
71  case IndexDescription: return QVariant::fromValue(m_description);
72  case IndexSimulator: return m_simulator.propertyByIndex(index.copyFrontRemoved());
73  default: return CValueObject::propertyByIndex(index);
74  }
75  }
76 
78  {
79  if (index.isMyself())
80  {
81  (*this) = variant.value<CDistributor>();
82  return;
83  }
84  if (IDatastoreObjectWithStringKey::canHandleIndex(index))
85  {
86  IDatastoreObjectWithStringKey::setPropertyByIndex(index, variant);
87  return;
88  }
89  if (IOrderable::canHandleIndex(index))
90  {
91  IOrderable::setPropertyByIndex(index, variant);
92  return;
93  }
94 
95  const auto i = index.frontCasted<ColumnIndex>();
96  switch (i)
97  {
98  case IndexAlias1: m_alias1 = variant.value<QString>(); break;
99  case IndexAlias2: m_alias2 = variant.value<QString>(); break;
100  case IndexDescription: m_description = variant.value<QString>(); break;
101  case IndexSimulator: m_simulator.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
102  default: CValueObject::setPropertyByIndex(index, variant); break;
103  }
104  }
105 
107  {
108  if (IDatastoreObjectWithStringKey::canHandleIndex(index))
109  {
110  return IDatastoreObjectWithStringKey::comparePropertyByIndex(index, compareValue);
111  }
112  if (IOrderable::canHandleIndex(index)) { return IOrderable::comparePropertyByIndex(index, compareValue); }
113 
114  const auto i = index.frontCasted<ColumnIndex>();
115  switch (i)
116  {
117  case IndexAlias1: return m_alias1.compare(compareValue.m_alias1, Qt::CaseInsensitive);
118  case IndexAlias2: return m_alias2.compare(compareValue.m_alias2, Qt::CaseInsensitive);
119  case IndexDescription: return m_description.compare(compareValue.getDescription(), Qt::CaseInsensitive);
120  case IndexSimulator:
121  return m_simulator.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.m_simulator);
122  default: break;
123  }
124  Q_ASSERT_X(false, Q_FUNC_INFO, "Compare failed");
125  return 0;
126  }
127 
129  {
130  Q_UNUSED(i18n)
131  QString s = QStringLiteral("Id: '%1'").arg(m_dbKey);
132  if (this->hasAlias1()) { s.append(" ").append(m_alias1); }
133  if (this->hasAlias2()) { s.append(" ").append(m_alias2); }
134  return s;
135  }
136 
137  bool CDistributor::hasCompleteData() const { return !m_description.isEmpty() && !m_dbKey.isEmpty(); }
138 
140  {
141  static const CLogCategoryList cats(CLogCategoryList(this).withValidation());
142  CStatusMessageList msgs;
143  if (!hasValidDbKey())
144  {
145  msgs.push_back(CStatusMessage(cats, CStatusMessage::SeverityError, u"Distributor: missing id"));
146  }
147  if (!hasDescription())
148  {
149  msgs.push_back(CStatusMessage(cats, CStatusMessage::SeverityError, u"Distributor: missing description"));
150  }
151  return msgs;
152  }
153 
154  void CDistributor::updateMissingParts(const CDistributor &otherDistributor)
155  {
156  if (!this->hasValidDbKey() && otherDistributor.hasValidDbKey())
157  {
158  // we have no DB data, but the other one has
159  // so we change roles. We take the DB object as base, and update our parts
160  CDistributor copy(otherDistributor);
161  copy.updateMissingParts(*this);
162  *this = copy;
163  return;
164  }
165 
166  if (!this->hasAlias1()) { this->setAlias1(otherDistributor.getAlias1()); }
167  if (!this->hasAlias2()) { this->setAlias1(otherDistributor.getAlias2()); }
168  if (!this->hasDescription()) { this->setDescription(otherDistributor.getDescription()); }
169  }
170 
172  {
173  if (!existsKey(json, prefix))
174  {
175  // when using relationship, this can be null
176  return {};
177  }
178 
179  const QString description(json.value(prefix % u"description").toString());
180  if (description.isEmpty())
181  {
182  // stub, only key, maybe also timestamps
183  CDistributor distributorStub;
184  distributorStub.setKeyVersionTimestampFromDatabaseJson(json, prefix);
185  return distributorStub;
186  }
187 
188  const CSimulatorInfo simulator = CSimulatorInfo::fromDatabaseJson(json, prefix);
189  const QString alias1(json.value(prefix % u"alias1").toString());
190  const QString alias2(json.value(prefix % u"alias2").toString());
191  Q_ASSERT_X(!description.isEmpty(), Q_FUNC_INFO, "Missing description");
192  CDistributor distributor("", description, alias1, alias2, simulator);
193  distributor.setKeyVersionTimestampFromDatabaseJson(json, prefix);
194  distributor.setLoadedFromDb(true);
195  return distributor;
196  }
197 
199  {
200  static const QString k("FSX");
201  return k;
202  }
203 
205  {
206  static const QString k("P3D");
207  return k;
208  }
209 
211  {
212  static const QString k("FS9");
213  return k;
214  }
215 
217  {
218  static const QString k("XP");
219  return k;
220  }
221 
223  {
224  static const QString k("FG");
225  return k;
226  }
227 
229  {
230  static const QSet<QString> fsFamily(
232  return fsFamily;
233  }
234 
236  {
237  static const QSet<QString> mp({ xplaneBlueBell(), xplaneXcsl() });
238  return mp;
239  }
240 
242  {
243  static const QString k("BB");
244  return k;
245  }
246 
248  {
249  static const QString k("XCSL");
250  return k;
251  }
252 
254  {
255  static const QString k("MSFS");
256  return k;
257  }
258 
260  {
261  static const QString k("MSFS2024");
262  return k;
263  }
264 
265  QString CDistributor::unifyKeyOrAlias(const QString &value)
266  {
267  return removeChars(value.trimmed().toUpper(), [](QChar c) { return !c.isLetterOrNumber(); });
268  }
269 
270 } // namespace swift::misc::simulation
A sequence of log categories.
Non-owning reference to a CPropertyIndex with a subset of its features.
Q_REQUIRED_RESULT CPropertyIndexRef copyFrontRemoved() const
Copy with first element removed.
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.
Definition: sequence.h:305
Streamable status message, e.g.
constexpr static auto SeverityError
Status severities.
Status messages, e.g. from Core -> GUI.
static bool canHandleIndex(CPropertyIndexRef index)
Can given index be handled.
Definition: orderable.cpp:31
int comparePropertyByIndex(CPropertyIndexRef index, const IOrderable &compareValue) const
Compare for index.
Definition: orderable.cpp:71
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
Definition: orderable.cpp:55
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
Definition: orderable.cpp:38
void setLoadedFromDb(bool loaded)
Mark as loaded from DB.
Definition: datastore.h:207
static bool existsKey(const QJsonObject &json, const QString &prefix=QString())
Is a key available?
Definition: datastore.cpp:188
bool hasValidDbKey() const
Has valid DB key.
Definition: datastore.h:195
const QString & getDbKey() const
Get DB key.
Definition: datastore.h:180
void setKeyVersionTimestampFromDatabaseJson(const QJsonObject &json, const QString &prefix=QString())
Set key and timestamp values.
Definition: datastore.cpp:180
void setDbKey(const QString &key)
Set the DB key.
Definition: datastore.h:192
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
Definition: mixinindex.h:158
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
Definition: mixinindex.h:165
Value object encapsulating information of software distributor.
Definition: distributor.h:33
void setDescription(const QString &description)
Set description.
Definition: distributor.h:62
QString getIdAndDescription() const
Get id and description.
Definition: distributor.cpp:28
static const QString & standardFS9()
Hardcoded keys for standard models.
static const QSet< QString > & standardAllFsFamily()
Hardcoded keys for standard models.
static const QString & xplaneXcsl()
Hardcoded keys for standard models.
int comparePropertyByIndex(CPropertyIndexRef index, const CDistributor &compareValue) const
Compare for index.
QVariant propertyByIndex(swift::misc::CPropertyIndexRef index) const
Property by index.
Definition: distributor.cpp:57
const QString & getDescription() const
Get description.
Definition: distributor.h:56
void setPropertyByIndex(swift::misc::CPropertyIndexRef index, const QVariant &variant)
Set property by index.
Definition: distributor.cpp:77
static const QSet< QString > & xplaneMostPopular()
Hardcoded keys for standard models.
static const QString & standardMsfs()
Hardcoded keys for standard models.
static const QString & standardXPlane()
Hardcoded keys for standard models.
bool matchesKeyOrAlias(const QString &keyOrAlias) const
Matches key or alias.
Definition: distributor.cpp:38
static const QString & standardFSX()
Hardcoded keys for standard models.
static const QString & standardFlightGear()
Hardcoded keys for standard models.
void updateMissingParts(const CDistributor &otherDistributor)
Update missing parts.
bool hasDescription() const
Has description.
Definition: distributor.h:65
bool hasCompleteData() const
Complete data?
QString convertToQString(bool i18n=false) const
Cast as QString.
static CDistributor fromDatabaseJson(const QJsonObject &json, const QString &prefix=QString())
Object from JSON.
static const QString & standardP3D()
Hardcoded keys for standard models.
static const QString & standardMsfs2024()
Hardcoded keys for standard models.
const QString & getAlias2() const
Get alias2.
Definition: distributor.h:71
swift::misc::CStatusMessageList validate() const
Validate data.
void setAlias1(const QString &alias)
Set alias1.
Definition: distributor.h:74
static const QString & xplaneBlueBell()
Hardcoded keys for standard models.
const QString & getAlias1() const
Get alias1.
Definition: distributor.h:68
CDistributor()=default
Default constructor.
bool matchesSimulator(const CSimulatorInfo &simulator) const
Matches simulator.
Definition: distributor.cpp:52
Simple hardcoded info about the corresponding simulator.
Definition: simulatorinfo.h:41
int comparePropertyByIndex(CPropertyIndexRef index, const CSimulatorInfo &compareValue) const
Cast as QString.
bool matchesAny(const CSimulatorInfo &otherInfo) const
Matches any simulator.
static CSimulatorInfo fromDatabaseJson(const QJsonObject &json, const QString &prefix)
From database JSON.
QString removeChars(const QString &s, F predicate)
Return a string with characters removed that match the given predicate.
Definition: stringutils.h:34
QJsonValue value(QLatin1StringView key) const const
QString toString() const const
QString & append(QChar ch)
QString arg(Args &&... args) const const
int compare(QLatin1StringView s1, const QString &s2, Qt::CaseSensitivity cs)
bool isEmpty() const const
QString toUpper() const const
QString trimmed() const const
CaseInsensitive
QVariant fromValue(T &&value)
T value() const &const
#define SWIFT_DEFINE_VALUEOBJECT_MIXINS(Namespace, Class)
Explicit template definition of mixins for a CValueObject subclass.
Definition: valueobject.h:67