7 #include <QDomDocument>
8 #include <QDomNodeList>
13 #include <QStandardPaths>
14 #include <QStringBuilder>
15 #include <QStringList>
27 using namespace swift::config;
29 namespace swift::misc::simulation::fscommon
31 const QStringList &CFsCommonUtil::getLogCategories()
33 static const QStringList cats({ CLogCategories::validation(), CLogCategories::driver() });
37 bool CFsCommonUtil::adjustFileDirectory(
CAircraftModel &model,
const QString &simObjectsDirectory)
40 if (simObjectsDirectory.isEmpty()) {
return false; }
43 const QString simObjectsDirectoryFix = CFileUtils::fixWindowsUncPath(simObjectsDirectory);
44 const QDir dir(simObjectsDirectoryFix);
45 if (!dir.exists()) {
return false; }
47 const QString lastSegment = u
'/' % CFileUtils::lastPathSegment(simObjectsDirectoryFix) % u
'/';
48 const int index = model.
getFileName().lastIndexOf(lastSegment);
49 if (index < 0) {
return false; }
50 const QString relPart = model.
getFileName().mid(index + lastSegment.length());
51 if (relPart.isEmpty()) {
return false; }
52 const QString newFile = CFileUtils::appendFilePathsAndFixUnc(simObjectsDirectory, relPart);
53 const QFileInfo nf(newFile);
54 if (!nf.exists()) {
return false; }
60 bool CFsCommonUtil::adjustFileDirectory(
CAircraftModel &model,
const QStringList &simObjectsDirectories)
62 for (
const QString &simObjectDir : simObjectsDirectories)
64 if (CFsCommonUtil::adjustFileDirectory(model, simObjectDir)) {
return true; }
69 int CFsCommonUtil::copyFsxTerrainProbeFiles(
const QString &simObjectDir,
CStatusMessageList &messages)
72 if (!CDirectoryUtils::existsUnemptyDirectory(CSwiftDirectories::shareTerrainProbeDirectory()))
75 u
"No terrain probe source files in '%1'")
76 << CSwiftDirectories::shareTerrainProbeDirectory());
80 if (simObjectDir.isEmpty())
83 u
"No simObject directory"));
87 QString targetDir = CFileUtils::appendFilePathsAndFixUnc(simObjectDir,
"Misc");
88 const QDir td(targetDir);
92 u
"Cannot access target directory '%1'")
97 const QString lastSegment = CFileUtils::lastPathSegment(CSwiftDirectories::shareTerrainProbeDirectory());
98 targetDir = CFileUtils::appendFilePathsAndFixUnc(targetDir, lastSegment);
99 const bool hasDir = td.mkpath(targetDir);
103 u
"Cannot create target directory '%1'")
109 CDirectoryUtils::copyDirectoryRecursively(CSwiftDirectories::shareTerrainProbeDirectory(), targetDir,
true);
111 u
"Copied %1 files from '%2' to '%3'")
112 << copied << CSwiftDirectories::shareTerrainProbeDirectory() << targetDir);
119 bool ignoreEmptyFileNames,
int stopAtFailedFiles,
120 std::atomic_bool &wasStopped)
127 stopAtFailedFiles, wasStopped, QString(),
true);
128 if (wasStopped || validModels.
isEmpty()) {
return msgs; }
136 static_cast<CFsCommonUtil *
>(
nullptr), CStatusMessage::SeverityError,
137 QStringLiteral(
"Removed '%1' non FS family model").arg(model.getModelStringAndDbKey()),
true);
139 if (wasStopped) {
break; }
144 QStringLiteral(
"Removed %1 non FS family models").arg(d),
true);
149 int removedCfgEntries = 0;
151 for (
const QString &fileName : fileNames)
154 if (wasStopped) {
break; }
162 QStringLiteral(
"'%1' removed because no longer in '%2'")
163 .arg(removedModel.getModelStringAndDbKey(), removedModel.getFileName()),
166 CAircraftModelList::addAsValidOrInvalidModel(removedModel,
false, validModels, invalidModels);
170 if (removedCfgEntries < 1)
173 QStringLiteral(
"Not removed any models, all OK!"),
true);
180 QStringLiteral(
"cfg validation, valid models: %1").arg(validModels.
size()),
true);
186 QStringLiteral(
"cfg validation, invalid models: %1").arg(invalidModels.
size()),
true);
196 bool ignoreEmptyFileNames,
int stopAtFailedFiles, std::atomic_bool &wasStopped,
const QString &simulatorDir)
198 const QString simObjectsDir = simulatorDir.
isEmpty() ? CFsDirectories::p3dSimObjectsDir() :
199 CFsDirectories::p3dSimObjectsDirFromSimDir(simulatorDir);
200 const QStringList simObjectPaths = CFsDirectories::p3dSimObjectsDirPlusAddOnXmlSimObjectsPaths(
201 simObjectsDir, CFsDirectories::guessP3DVersion(simObjectsDir));
202 return CFsCommonUtil::validateSimObjectsPath(QSet<QString>(simObjectPaths.begin(), simObjectPaths.end()),
203 models, validModels, invalidModels, ignoreEmptyFileNames,
204 stopAtFailedFiles, wasStopped);
210 bool ignoreEmptyFileNames,
int stopAtFailedFiles,
211 std::atomic_bool &stopped,
const QString &simulatorDir)
213 Q_UNUSED(simulatorDir)
214 const QStringList simObjectPaths = CFsDirectories::fsxSimObjectsDirPlusAddOnXmlSimObjectsPaths();
215 return CFsCommonUtil::validateSimObjectsPath(QSet<QString>(simObjectPaths.begin(), simObjectPaths.end()),
216 models, validModels, invalidModels, ignoreEmptyFileNames,
217 stopAtFailedFiles, stopped);
223 bool ignoreEmptyFileNames,
int stopAtFailedFiles,
224 std::atomic_bool &stopped,
const QString &simulatorDir)
226 Q_UNUSED(simulatorDir)
227 const QStringList simObjectPaths = CFsDirectories::msfsSimObjectsDirPath();
228 return CFsCommonUtil::validateSimObjectsPath(QSet<QString>(simObjectPaths.begin(), simObjectPaths.end()),
229 models, validModels, invalidModels, ignoreEmptyFileNames,
230 stopAtFailedFiles, stopped);
235 bool ignoreEmptyFileNames,
int stopAtFailedFiles, std::atomic_bool &stopped,
const QString &simulatorDir)
237 Q_UNUSED(simulatorDir)
238 const QStringList simObjectPaths = CFsDirectories::msfs2024SimObjectsDirPath();
239 return CFsCommonUtil::validateSimObjectsPath(QSet<QString>(simObjectPaths.begin(), simObjectPaths.end()),
240 models, validModels, invalidModels, ignoreEmptyFileNames,
241 stopAtFailedFiles, stopped);
245 CFsCommonUtil::validateSimObjectsPath(
const QSet<QString> &simObjectDirs,
const CAircraftModelList &models,
247 bool ignoreEmptyFileNames,
int stopAtFailedFiles, std::atomic_bool &stopped)
250 if (simObjectDirs.isEmpty())
253 .validationInfo(u
"No SimObject directories from cfg files, skipping validation"));
258 sortedModels.sortByFileName();
259 if (sortedModels.isEmpty())
262 CStatusMessage(
static_cast<CFsCommonUtil *
>(
nullptr)).validationInfo(u
"No models to validate"));
267 const QString simObjDirs =
joinStringSet(simObjectDirs,
", ");
269 .validationInfo(u
"Validating %1 models against %2 SimObjects path(s): '%3'")
270 << models.
size() << simObjectDirs.size() << simObjDirs);
274 for (
const CAircraftModel &model : models)
276 if (!model.hasFileName())
278 if (ignoreEmptyFileNames) {
continue; }
279 msgs.
push_back(CStatusMessage(
static_cast<CFsCommonUtil *
>(
nullptr))
280 .validationWarning(u
"No file name for model '%1'")
281 << model.getModelString());
282 CAircraftModelList::addAsValidOrInvalidModel(model,
false, validModels, invalidModels);
287 for (
const QString &path : simObjectDirs)
289 if (!model.isInPath(path, CFileUtils::osFileNameCaseSensitivity())) {
continue; }
293 CAircraftModelList::addAsValidOrInvalidModel(model, ok, validModels, invalidModels);
296 msgs.
push_back(CStatusMessage(
static_cast<CFsCommonUtil *
>(
nullptr))
297 .validationWarning(u
"Model '%1' '%2' in none of the %3 SimObjects path(s)")
298 << model.getModelString() << model.getFileName() << simObjectDirs.size());
302 if (stopAtFailedFiles > 0 && failed >= stopAtFailedFiles)
305 msgs.
push_back(CStatusMessage(
static_cast<CFsCommonUtil *
>(
nullptr))
306 .validationWarning(u
"Stopping after %1 failed models")
size_type size() const
Returns number of elements in the sequence.
void push_back(const T &value)
Appends an element at the end of the sequence.
void clear()
Removes all elements in the sequence.
bool isEmpty() const
Synonym for empty.
Streamable status message, e.g.
Status messages, e.g. from Core -> GUI.
Aircraft model (used by another pilot, my models on disk)
bool hasExistingCorrespondingFile() const
Does the corresponding file exist?
void setFileName(const QString &fileName)
File name.
bool hasFileName() const
File name?
const QString & getFileName() const
File name (corresponding data for simulator, only available if representing simulator model.
Value object encapsulating a list of aircraft models.
CAircraftModelList removeIfFileButNotInSet(const QString &fileName, const QSet< QString > &modelStrings)
Remove those models of a particular file, but not in the given set.
QSet< QString > getAllFileNames() const
All file names.
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.)
int removeIfNotFsFamily()
Remove if NOT FS family model, ie. FSX/P3D/FS9/MSFS.
CAircraftModelList findNonFsFamilyModels() const
All models NOT of the FS (FSX, P3D, FS9, MSFS) family.
void sortByFileName()
Sort by file path.
Utility, providing FS aircraft.cfg entries.
QSet< QString > getTitleSetUpperCase() const
Titles as set in upper case.
SWIFT_MISC_EXPORT QString joinStringSet(const QSet< QString > &set, const QString &separator)
Convert string to bool.