swift
aircraftmodelutils.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2016 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #include <algorithm>
7 
8 #include "misc/directoryutils.h"
11 #include "misc/swiftdirectories.h"
12 #include "misc/verify.h"
13 
14 namespace swift::misc::simulation
15 {
17  const CAircraftModelList &vPilotModels, bool force)
18  {
19  if (vPilotModels.isEmpty() || modelToBeModified.isEmpty()) { return false; }
20  for (CAircraftModel &simModel : modelToBeModified)
21  {
22  if (!force && simModel.hasValidAircraftAndAirlineDesignator()) { continue; } // already done
23  const CAircraftModel vPilotModel(vPilotModels.findFirstByModelStringOrDefault(simModel.getModelString()));
24  if (!vPilotModel.hasValidDbKey())
25  {
26  continue; // not found
27  }
28  simModel.updateMissingParts(vPilotModel, false);
29  }
30  return true;
31  }
32 
34  {
35  if (models.isEmpty()) { return {}; }
36  static const QString emptyDesignator = "----";
37  static const QString colorLiveryDesignator = "-C-";
38 
40 
41  // create an empty map of all airlines
42  const QMap<QString, CAircraftModelList> emptyAirlineDesignatorMap;
43  CAircraftModelList sortedByAircraft(models);
45 
46  for (const CAircraftModel &model : std::as_const(sortedByAircraft))
47  {
48  const QString aircraftIcao(model.hasAircraftDesignator() ? model.getAircraftIcaoCodeDesignator() :
49  emptyDesignator);
50  if (!modelsByDesignator.contains(aircraftIcao))
51  {
52  modelsByDesignator.insert(aircraftIcao, emptyAirlineDesignatorMap);
53  }
54  QMap<QString, CAircraftModelList> &airlineModels = modelsByDesignator[aircraftIcao];
55  const QString airlineIcao(model.getLivery().isColorLivery() ? colorLiveryDesignator :
56  model.hasAirlineDesignator() ? model.getAirlineIcaoCodeDesignator() :
57  emptyDesignator);
58  if (airlineModels.contains(airlineIcao)) { airlineModels[airlineIcao].push_back(model); }
59  else { airlineModels.insert(airlineIcao, CAircraftModelList({ model })); }
60  }
61 
62  // to HTML
63  QString html("<table>\n");
64  QStringList airlineIcaos = models.getAirlineVDesignators().values();
65  airlineIcaos.sort();
66  airlineIcaos.push_front(colorLiveryDesignator);
67  airlineIcaos.push_back(emptyDesignator);
68  QStringList aircraftIcaos = modelsByDesignator.keys();
69  aircraftIcaos.sort();
70 
71  // header
72  html += "<thead><tr>\n"
73  "<th></th>";
74  for (const QString &airline : std::as_const(airlineIcaos))
75  {
76  html += "<th>";
77  html += airline;
78  html += "</th>";
79  }
80  html += "\n</tr></thead>\n"
81  "<tbody>\n";
82 
83  // fill data
84  for (const QString &aircraftIcao : std::as_const(aircraftIcaos))
85  {
86  html += "<tr>\n"
87  " <th>";
88  html += aircraftIcao;
89  html += "</th>\n";
90 
91  const QMap<QString, CAircraftModelList> &airlineModels = modelsByDesignator[aircraftIcao];
92  for (const QString &airline : std::as_const(airlineIcaos))
93  {
94  if (airlineModels.contains(airline))
95  {
96  html += " <td>";
97  const CAircraftModelList &models(airlineModels[airline]);
98  html += "<a>";
99  html += QString::number(models.size());
100  html += "</a><div class=\"mouseoverdisplay\">";
101  html += models.asHtmlSummary();
102  html += "</div>"
103  "</td>\n";
104  }
105  else { html += " <td></td>\n"; }
106  }
107  html += "</tr>\n";
108  }
109  html += "</tbody>\n"
110  "</table>\n";
111  return html;
112  }
113 
115  const QString &tempDir)
116  {
117  Q_ASSERT_X(!tempDir.isEmpty(), Q_FUNC_INFO, "Need directory");
118  if (models.isEmpty()) { return {}; }
119  const QString html = createIcaoAirlineAircraftHtmlMatrix(models);
120  if (html.isEmpty()) { return {}; }
121 
122  QDir dir(tempDir);
123  SWIFT_VERIFY_X(dir.exists(), Q_FUNC_INFO, "Directory does not exist");
124  if (!dir.exists()) { return {}; }
125 
127  const QString fn("airlineAircraftMatrix.html");
128  const bool ok = CFileUtils::writeStringToFile(htmlTemplate.arg(html), dir.absoluteFilePath(fn));
129  return ok ? dir.absoluteFilePath(fn) : "";
130  }
131 
133  const CAircraftModelList &models,
134  CAircraftModelList &validModels,
135  CAircraftModelList &invalidModels, bool ignoreEmpty,
136  int stopAtFailedFiles, std::atomic_bool &wasStopped,
137  const QString &simulatorDir)
138  {
139  // some generic tests
141  CStatusMessageList msgs;
142  if (models.isEmpty())
143  {
144  msgs.push_back(CStatusMessage(cats, CStatusMessage::SeverityError, u"No models", true));
145  return msgs;
146  }
147 
148  const int noDb = models.size() - models.countWithValidDbKey();
149  if (noDb > 0)
150  {
152  QStringLiteral("%1 models without DB data, is this intended?").arg(noDb),
153  true));
154  const QString ms = models.findWithoutValidDbKey(5).getModelStringList().join(", ");
156  QStringLiteral("Some of the non DB models are: '%1'").arg(ms), true));
157  }
158 
159  const int noExcluded = models.countByMode(CAircraftModel::Exclude);
160  if (noExcluded > 0)
161  {
164  QStringLiteral("%1 models marked as excluded, is this intended?").arg(noExcluded), true));
165  const QString ms = models.findAllExcludedModels(5).getModelStringList().join(", ");
167  QStringLiteral("Some of the excluded models are: '%1'").arg(ms), true));
168  }
169 
170  // specific checks for FSX/XPlane/FG
171  CStatusMessageList specificTests;
173  {
175  models, validModels, invalidModels, ignoreEmpty, stopAtFailedFiles, wasStopped);
176  specificTests.push_back(specificTests1);
177 
178  if (simulator.isP3D())
179  {
181  models, validModels, invalidModels, ignoreEmpty, stopAtFailedFiles, wasStopped, simulatorDir);
182  specificTests.push_back(specificTests2);
183  }
184  else if (simulator.isFSX())
185  {
187  models, validModels, invalidModels, ignoreEmpty, stopAtFailedFiles, wasStopped, simulatorDir);
188  specificTests.push_back(specificTests2);
189  }
190  else if (simulator.isMSFS())
191  {
193  models, validModels, invalidModels, ignoreEmpty, stopAtFailedFiles, wasStopped, simulatorDir);
194  specificTests.push_back(specificTests2);
195  }
196  else if (simulator.isMSFS2024())
197  {
199  models, validModels, invalidModels, ignoreEmpty, stopAtFailedFiles, wasStopped, simulatorDir);
200  specificTests.push_back(specificTests2);
201  }
202  }
203  else if (simulator.isXPlane() || models.isLikelyXPlaneModelList())
204  {
205  specificTests = models.validateFiles(validModels, invalidModels, ignoreEmpty, stopAtFailedFiles, wasStopped,
206  simulatorDir);
207  }
208  else
209  {
210  specificTests =
211  models.validateFiles(validModels, invalidModels, ignoreEmpty, stopAtFailedFiles, wasStopped, {});
212  }
213 
214  msgs.push_back(specificTests);
215  return msgs;
216  }
217 } // namespace swift::misc::simulation
static bool writeStringToFile(const QString &content, const QString &fileNameAndPath)
Write string to text file.
Definition: fileutils.cpp:40
static QString readFileToString(const QString &fileNameAndPath)
Read file into string.
Definition: fileutils.cpp:68
static const QString & matching()
Matching.
A sequence of log categories.
size_type size() const
Returns number of elements in the sequence.
Definition: sequence.h:273
void sortBy(K1 key1, Keys... keys)
In-place sort by some particular key(s).
Definition: sequence.h:576
void push_back(const T &value)
Appends an element at the end of the sequence.
Definition: sequence.h:305
bool isEmpty() const
Synonym for empty.
Definition: sequence.h:285
Streamable status message, e.g.
constexpr static auto SeverityError
Status severities.
constexpr static auto SeverityWarning
Status severities.
Status messages, e.g. from Core -> GUI.
static const QString & htmlTemplateFilePath()
HTML template.
int countWithValidDbKey(bool withKey) const
Number of objects with/without key.
bool hasValidDbKey() const
Has valid DB key.
Definition: datastore.h:102
Aircraft model (used by another pilot, my models on disk)
Definition: aircraftmodel.h:71
const QString & getAircraftIcaoCodeDesignator() const
Aircraft ICAO code designator.
Value object encapsulating a list of aircraft models.
bool isLikelyFsFamilyModelList() const
Is this here a FS family (P3D/FSX/FS9/MSFS) model list?
int countByMode(CAircraftModel::ModelMode mode) const
Count by mode.
QStringList getModelStringList(bool sort=true) const
Model strings.
CAircraftModelList findAllExcludedModels() const
All included/excluded models.
CAircraftModel findFirstByModelStringOrDefault(const QString &modelString, Qt::CaseSensitivity sensitivity=Qt::CaseInsensitive) const
Find first by model string.
QSet< QString > getAirlineVDesignators() const
Airline virtual designators.
CAircraftModelList findWithoutValidDbKey() const
With/without DB key.
CStatusMessageList validateFiles(CAircraftModelList &validModels, CAircraftModelList &invalidModels, bool ignoreEmptyFileNames, int stopAtFailedFiles, std::atomic_bool &wasStopped, const QString &simRootDirectory, bool alreadySortedByFn=false) const
Validate files (file exists etc.)
QString asHtmlSummary() const
As HTML summary.
bool isLikelyXPlaneModelList() const
Is this here a XPlane model list?
static QString createIcaoAirlineAircraftHtmlMatrixFile(const swift::misc::simulation::CAircraftModelList &models, const QString &tempDir)
Matrix airlines/aircraft ICAOs.
static CStatusMessageList validateModelFiles(const CSimulatorInfo &simulator, const CAircraftModelList &models, CAircraftModelList &validModels, CAircraftModelList &invalidModels, bool ignoreEmpty, int stopAtFailedFiles, std::atomic_bool &wasStopped, const QString &simulatorDir)
Validate aircraft.cfg entries.
static bool mergeWithVPilotData(swift::misc::simulation::CAircraftModelList &modelToBeModified, const swift::misc::simulation::CAircraftModelList &vPilotModels, bool force=false)
Merge with vPilot data if possible.
static QString createIcaoAirlineAircraftHtmlMatrix(const swift::misc::simulation::CAircraftModelList &models)
Matrix airlines/aircraft ICAOs.
Simple hardcoded info about the corresponding simulator.
Definition: simulatorinfo.h:41
bool isMicrosoftOrPrepare3DSimulator() const
Microsoft Simulator or P3D?
static CStatusMessageList validateAircraftConfigFiles(const CAircraftModelList &models, CAircraftModelList &validModels, CAircraftModelList &invalidModels, bool ignoreEmptyFileNames, int stopAtFailedFiles, std::atomic_bool &wasStopped)
Validate aircraft.cfg entries (sometimes also sim.cfg)
static CStatusMessageList validateMSFSSimObjectsPath(const CAircraftModelList &models, CAircraftModelList &validModels, CAircraftModelList &invalidModels, bool ignoreEmptyFileNames, int stopAtFailedFiles, std::atomic_bool &wasStopped, const QString &simulatorDir)
Validate if known SimObjects path are used.
static CStatusMessageList validateP3DSimObjectsPath(const CAircraftModelList &models, CAircraftModelList &validModels, CAircraftModelList &invalidModels, bool ignoreEmptyFileNames, int stopAtFailedFiles, std::atomic_bool &wasStopped, const QString &simulatorDir)
Validate if known SimObjects path are used.
static CStatusMessageList validateMSFS2024SimObjectsPath(const CAircraftModelList &models, CAircraftModelList &validModels, CAircraftModelList &invalidModels, bool ignoreEmptyFileNames, int stopAtFailedFiles, std::atomic_bool &wasStopped, const QString &simulatorDir)
Validate if known SimObjects path are used.
static CStatusMessageList validateFSXSimObjectsPath(const CAircraftModelList &models, CAircraftModelList &validModels, CAircraftModelList &invalidModels, bool ignoreEmptyFileNames, int stopAtFailedFiles, std::atomic_bool &wasStopped, const QString &simulatorDir)
Validate if known SimObjects path are used.
#define SWIFT_VERIFY_X(COND, WHERE, WHAT)
A weaker kind of assert.
Definition: verify.h:26