swift
aircraftmodelloaderflightgear.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2019 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
4 #include "misc/simulation/flightgear/aircraftmodelloaderflightgear.h"
5 
6 #include <QDirIterator>
7 
9 namespace swift::misc::simulation::flightgear
10 {
11 
13  {
14  return !m_parserWorker || m_parserWorker->isFinished();
15  ;
16  }
17 
19  : simulation::IAircraftModelLoader(simulation::CSimulatorInfo::fg(), parent)
20  {}
21 
23  {
24  // that should be safe as long as the worker uses deleteLater (which it does)
25  if (m_parserWorker) { m_parserWorker->waitForFinished(); }
26  }
27 
29  {
31  const CStatusMessage m = CStatusMessage(this, CStatusMessage::SeverityInfo, u"Flightgear updated '%1' models")
32  << models.size();
34  }
35 
36  CAircraftModelList CAircraftModelLoaderFlightgear::parseFlyableAirplanes(const QString &rootDirectory,
37  const QStringList &excludeDirectories)
38  {
39  Q_UNUSED(excludeDirectories);
40  if (rootDirectory.isEmpty()) { return {}; }
41  CAircraftModelList installedModels;
42 
43  QDir searchPath(rootDirectory);
44  searchPath.setNameFilters(QStringList() << "*-set.xml");
45  QDirIterator aircraftIt(searchPath, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
46 
47  while (aircraftIt.hasNext())
48  {
49  aircraftIt.next();
50  if (CFileUtils::isExcludedDirectory(aircraftIt.fileInfo(), excludeDirectories, Qt::CaseInsensitive))
51  {
52  continue;
53  }
54  if (aircraftIt.filePath().contains("/AI/Aircraft")) { continue; }
55  CAircraftModel model;
56  QString modelName = aircraftIt.fileName();
57  modelName = modelName.remove("-set.xml");
58  model.setName(modelName);
59  model.setModelString(getModelString(aircraftIt.fileName(), false));
60  model.setModelType(CAircraftModel::TypeOwnSimulatorModel);
61  model.setSimulator(CSimulatorInfo::fg());
62  model.setFileDetailsAndTimestamp(aircraftIt.fileInfo());
63  model.setModelMode(CAircraftModel::Exclude);
64  addUniqueModel(model, installedModels);
65  }
66 
67  return installedModels;
68  }
69 
70  CAircraftModelList CAircraftModelLoaderFlightgear::parseAIAirplanes(const QString &rootDirectory,
71  const QStringList &excludeDirectories)
72  {
73  Q_UNUSED(excludeDirectories);
74  if (rootDirectory.isEmpty()) { return {}; }
75 
76  CAircraftModelList installedModels;
77 
78  QDir searchPath(rootDirectory);
79  searchPath.setNameFilters(QStringList() << "*.xml");
80  QDirIterator aircraftIt(searchPath, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
81 
82  while (aircraftIt.hasNext())
83  {
84  aircraftIt.next();
85  if (CFileUtils::isExcludedDirectory(aircraftIt.fileInfo(), excludeDirectories, Qt::CaseInsensitive))
86  {
87  continue;
88  }
89  CAircraftModel model;
90  QString modelName = aircraftIt.fileName();
91  modelName = modelName.remove(".xml");
92  model.setName(modelName);
93  model.setModelString(getModelString(aircraftIt.filePath(), true));
94  model.setModelType(CAircraftModel::TypeOwnSimulatorModel);
95  model.setSimulator(CSimulatorInfo::fg());
96  model.setFileDetailsAndTimestamp(aircraftIt.fileInfo());
97  model.setModelMode(CAircraftModel::Include);
98  addUniqueModel(model, installedModels);
99  }
100 
101  return installedModels;
102  }
103 
104  void CAircraftModelLoaderFlightgear::addUniqueModel(const CAircraftModel &model, CAircraftModelList &models)
105  {
106  // TODO Add check
107  models.push_back(model);
108  }
109 
110  CAircraftModelList CAircraftModelLoaderFlightgear::performParsing(const QStringList &rootDirectories,
111  const QStringList &excludeDirectories)
112  {
113  CAircraftModelList allModels;
114  for (const QString &rootDirectory : rootDirectories)
115  {
116  QString dir = rootDirectory;
117  dir.replace('\\', '/');
118  if (dir.contains("/AI/Aircraft")) { allModels.push_back(parseAIAirplanes(dir, excludeDirectories)); }
119  else { allModels.push_back(parseFlyableAirplanes(dir, excludeDirectories)); }
120  }
121 
122  return allModels;
123  }
124 
126  IAircraftModelLoader::LoadMode mode, const IAircraftModelLoader::ModelConsolidationCallback &modelConsolidation,
127  const QStringList &modelDirectories)
128  {
129  const CSimulatorInfo simulator = CSimulatorInfo::fg();
130  const QStringList modelDirs = this->getInitializedModelDirectories(modelDirectories, simulator);
131  const QStringList excludedDirectoryPatterns(
133 
134  if (mode.testFlag(LoadInBackground))
135  {
136  if (m_parserWorker && !m_parserWorker->isFinished()) { return; }
137  emit this->diskLoadingStarted(simulator, mode);
138 
139  m_parserWorker = CWorker::fromTask(this, "CAircraftModelLoaderFlightgear::performParsing",
140  [this, modelDirs, excludedDirectoryPatterns, modelConsolidation]() {
141  auto models =
142  this->performParsing(modelDirs, excludedDirectoryPatterns);
143  if (modelConsolidation) { modelConsolidation(models, true); }
144  return models;
145  });
146  m_parserWorker->thenWithResult<CAircraftModelList>(this, [=](const auto &models) {
147  this->updateInstalledModels(models);
149  emit this->loadingFinished(m_loadingMessages, simulator, ParsedData);
150  });
151  }
152  else if (mode.testFlag(LoadDirectly))
153  {
154  emit this->diskLoadingStarted(simulator, mode);
155  CAircraftModelList models(this->performParsing(modelDirs, excludedDirectoryPatterns));
156  this->updateInstalledModels(models);
157  }
158  }
159 
160  QString CAircraftModelLoaderFlightgear::getModelString(const QString &fileName, bool ai)
161  {
162  QString modelString = "FG ";
163  QString f;
164  if (ai)
165  {
166  modelString.append("AI ");
167  f = fileName.mid(fileName.indexOf("Aircraft") + 9);
168  f.remove(".xml");
169  }
170  else
171  {
172  f = fileName;
173  f.remove("-set.xml");
174  }
175 
176  modelString.append(f);
177  return modelString;
178  }
179 } // namespace swift::misc::simulation::flightgear
static bool isExcludedDirectory(const QDir &directory, const QStringList &excludeDirectories, Qt::CaseSensitivity cs=osFileNameCaseSensitivity())
Directory to be excluded?
Definition: fileutils.cpp:242
size_type size() const
Returns number of elements in the sequence.
Definition: sequence.h:273
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 SeverityInfo
Status severities.
static CWorker * fromTask(QObject *owner, const QString &name, F &&task)
Returns a new worker object which lives in a new thread.
Definition: worker.h:201
void freezeOrder()
Current order of list will be new order values.
@ TypeOwnSimulatorModel
represents own simulator model (AI model, model on disk)
Definition: aircraftmodel.h:84
Value object encapsulating a list of aircraft models.
Simple hardcoded info about the corresponding simulator.
Definition: simulatorinfo.h:41
static const CSimulatorInfo & fg()
Const simulator info objects.
Load the aircraft for a simulator.
std::function< int(swift::misc::simulation::CAircraftModelList &, bool)> ModelConsolidationCallback
Callback to consolidate data, normally with DB data.
QStringList getInitializedModelDirectories(const QStringList &modelDirectories, const CSimulatorInfo &simulator) const
Get model directories from settings if empty, otherwise checked and UNC path fixed.
void loadingFinished(const CStatusMessageList &status, const CSimulatorInfo &simulator, IAircraftModelLoader::LoadFinishedInfo info)
Parsing is finished or cache has been loaded.
void diskLoadingStarted(const CSimulatorInfo &simulator, IAircraftModelLoader::LoadMode loadMode)
Disk loading started.
settings::CMultiSimulatorSettings m_settings
settings
CStatusMessageList m_loadingMessages
loading messages
@ LoadInBackground
load in background, asyncronously
@ LoadDirectly
load synchronously (blocking), normally for testing
void setModelsForSimulator(const CAircraftModelList &models, const CSimulatorInfo &simulator)
Set models.
Definition: modelcaches.h:597
void startLoadingFromDisk(LoadMode mode, const ModelConsolidationCallback &modelConsolidation, const QStringList &modelDirectories)
Start the loading process from disk.
void updateInstalledModels(const CAircraftModelList &models)
Parsed or injected models.
QStringList getModelExcludeDirectoryPatternsOrDefault(const CSimulatorInfo &simulator) const
Model exclude patterns per simulator.