diff --git a/src/blackmisc/fileutils.cpp b/src/blackmisc/fileutils.cpp index eb2cc6819..db382ac80 100644 --- a/src/blackmisc/fileutils.cpp +++ b/src/blackmisc/fileutils.cpp @@ -223,6 +223,27 @@ namespace BlackMisc return relativeDirectories; } + bool CFileUtils::sameDirectories(const QStringList &dirs1, const QStringList &dirs2, Qt::CaseSensitivity cs) + { + // clean up + QStringList dirs1Cleaned(dirs1); + QStringList dirs2Cleaned(dirs2); + dirs1Cleaned.removeAll(""); + dirs1Cleaned.removeDuplicates(); + dirs2Cleaned.removeAll(""); + dirs2Cleaned.removeDuplicates(); + if (dirs1Cleaned.size() != dirs2Cleaned.size()) { return false; } + + int d2 = 0; + dirs1Cleaned.sort(cs); + dirs2Cleaned.sort(cs); + for (const QString &d1 : dirs1) + { + if (!stringCompare(d1, dirs2.at(d2), cs)) { return false; } + } + return true; + } + Qt::CaseSensitivity CFileUtils::osFileNameCaseSensitivity() { return CBuildConfig::isRunningOnWindowsNtPlatform() ? Qt::CaseInsensitive : Qt::CaseSensitive; diff --git a/src/blackmisc/fileutils.h b/src/blackmisc/fileutils.h index 388038fc6..b5f3614a0 100644 --- a/src/blackmisc/fileutils.h +++ b/src/blackmisc/fileutils.h @@ -107,6 +107,9 @@ namespace BlackMisc //! \remark unlike QDir::relativePath here reltive paths are only created when a directory is a subdir of rootDirectory static QStringList makeDirectoriesRelative(const QStringList &directories, const QString &rootDirectory, Qt::CaseSensitivity cs = osFileNameCaseSensitivity()); + //! Same directories, order in list does not matter and lists are cleaned up + static bool sameDirectories(const QStringList &dirs1, const QStringList &dirs2, Qt::CaseSensitivity cs = osFileNameCaseSensitivity()); + //! Case sensitivity for current OS static Qt::CaseSensitivity osFileNameCaseSensitivity(); diff --git a/src/blackmisc/simulation/fscommon/fscommonutil.cpp b/src/blackmisc/simulation/fscommon/fscommonutil.cpp index 60b139357..26068546d 100644 --- a/src/blackmisc/simulation/fscommon/fscommonutil.cpp +++ b/src/blackmisc/simulation/fscommon/fscommonutil.cpp @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include @@ -207,6 +209,16 @@ namespace BlackMisc return dir; } + QStringList CFsCommonUtil::p3dSimObjectsDirPlusAddOnSimObjectsDirs(const QString &simObjectsDir) + { + // finding the user settings only works on P3D machine + const QSet allP3dAddOnSimObjectPaths = CFsCommonUtil::allP3dAddOnSimObjectPaths("v4"); + QStringList all(allP3dAddOnSimObjectPaths.toList()); + all.push_front(simObjectsDir.isEmpty() ? p3dSimObjectsDir() : simObjectsDir); + all.sort(Qt::CaseInsensitive); + return all; + } + QString CFsCommonUtil::p3dSimObjectsDirFromSimDir(const QString &simDir) { if (simDir.isEmpty()) { return QStringLiteral(""); } @@ -402,6 +414,7 @@ namespace BlackMisc const QStringList entries = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot); for (const QString &entry : entries) { + // right version or just one file if (entry.contains(versionHint, Qt::CaseInsensitive)) { const QString f = CFileUtils::appendFilePaths(d.absolutePath(), entry, cfgFile); @@ -442,13 +455,34 @@ namespace BlackMisc QSet simObjectPaths; for (const QString &addOnPath : addOnPaths) { - const QString so = CFileUtils::appendFilePaths(addOnPath, "SimObjects"); - const QFileInfo fi(so); - if (!checked || fi.exists()) { simObjectPaths.insert(fi.absolutePath()); } + const QString filename = CFileUtils::appendFilePaths(addOnPath, "add-on.xml"); + QDomDocument doc; + QFile file(filename); + if (!file.open(QIODevice::ReadOnly) || !doc.setContent(&file)) { continue; } + const QDomNodeList components = doc.elementsByTagName("AddOn.Component"); + for (int i = 0; i < components.size(); i++) + { + const QDomNode component = components.item(i); + const QDomElement category = component.firstChildElement("Category"); + const QString categoryValue = category.text(); + if (!caseInsensitiveStringCompare(categoryValue, QStringLiteral("SimObjects"))) { continue; } + const QDomElement path = component.firstChildElement("Path"); + const QString pathValue = path.text(); + if (pathValue.isEmpty()) { continue; } + if (!checked || QDir(pathValue).exists()) { simObjectPaths.insert(CFileUtils::normalizeFilePathToQtStandard(pathValue)); } + } } return simObjectPaths; } + QSet CFsCommonUtil::allP3dAddOnSimObjectPaths(const QString &versionHint) + { + const QStringList configFiles = CFsCommonUtil::findP3dAddOnConfigFiles(versionHint).toList(); + const QStringList addOnPaths = CFsCommonUtil::allP3dAddOnPaths(configFiles, true).toList(); + const QSet all = CFsCommonUtil::allP3dAddOnSimObjectPaths(addOnPaths, true); + return all; + } + QStringList CFsCommonUtil::findFsxConfigFiles() { const QStringList locations = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation); diff --git a/src/blackmisc/simulation/fscommon/fscommonutil.h b/src/blackmisc/simulation/fscommon/fscommonutil.h index dfb1c703b..ef8cd39c4 100644 --- a/src/blackmisc/simulation/fscommon/fscommonutil.h +++ b/src/blackmisc/simulation/fscommon/fscommonutil.h @@ -57,9 +57,12 @@ namespace BlackMisc //! P3D's simObject directory from registry static const QString &p3dSimObjectsDirFromRegistry(); - //! P3D's sim object dir, resolved from multiple sources + //! P3D's simObject dir, resolved from multiple sources static const QString &p3dSimObjectsDir(); + //! P3D's simObject dir and the add on dirs + static QStringList p3dSimObjectsDirPlusAddOnSimObjectsDirs(const QString &simObjectsDir = ""); + //! P3D aircraft dir, relative to simulator directory static QString p3dSimObjectsDirFromSimDir(const QString &simDir); @@ -93,10 +96,10 @@ namespace BlackMisc //! Copy the terrain probe static int copyFsxTerrainProbeFiles(const QString &simObjectDir, CStatusMessageList &messages); - //! Find the config files + //! Find the config files (add-ons.cfg) //! \note C:/Users/Joe Doe/AppData/Roaming/Lockheed Martin/Prepar3D v4 //! \param versionHint like "v4" - static QSet findP3dAddOnConfigFiles(const QString &versionHint); + static QSet findP3dAddOnConfigFiles(const QString &versionHint = "v4"); //! All add-on paths from the config files static QSet allP3dAddOnPaths(const QStringList &addOnConfigsFiles, bool checked); @@ -104,7 +107,10 @@ namespace BlackMisc //! All add-on paths from the config files static QSet allP3dAddOnSimObjectPaths(const QStringList &addOnPaths, bool checked); - //! Find the config files + //! All add-on paths from the config files + static QSet allP3dAddOnSimObjectPaths(const QString &versionHint = "v4"); + + //! Find the config files (fsx.cfg) // C:/Users/Joe Doe/AppData/Roaming/Lockheed Martin/Prepar3D v4 static QStringList findFsxConfigFiles(); diff --git a/src/blackmisc/simulation/settings/simulatorsettings.cpp b/src/blackmisc/simulation/settings/simulatorsettings.cpp index 5582bf75a..be4f7f725 100644 --- a/src/blackmisc/simulation/settings/simulatorsettings.cpp +++ b/src/blackmisc/simulation/settings/simulatorsettings.cpp @@ -501,7 +501,9 @@ namespace BlackMisc case CSimulatorInfo::FG: break; case CSimulatorInfo::FS9: dirs = QStringList({CFsCommonUtil::fs9AircraftDirFromSimDir(s)}); break; case CSimulatorInfo::FSX: dirs = QStringList({CFsCommonUtil::fsxSimObjectsDirFromSimDir(s)}); break; - case CSimulatorInfo::P3D: dirs = QStringList({CFsCommonUtil::p3dSimObjectsDirFromSimDir(s)}); break; + case CSimulatorInfo::P3D: + dirs = QStringList(CFsCommonUtil::p3dSimObjectsDirPlusAddOnSimObjectsDirs(CFsCommonUtil::p3dSimObjectsDirFromSimDir(s))); + break; case CSimulatorInfo::XPLANE: dirs = QStringList({CXPlaneUtil::modelDirectoriesFromSimDir(s)}); break; default: break; } @@ -521,10 +523,8 @@ namespace BlackMisc { static const QStringList empty; if (!m_genericSettings.hasModelDirectories()) { return empty; } - if (m_genericSettings.getModelDirectories() == CSpecializedSimulatorSettings::defaultModelDirectories(m_simulator)) - { - return empty; - } + const QStringList defaultDirectories = CSpecializedSimulatorSettings::defaultModelDirectories(m_simulator); + if (CFileUtils::sameDirectories(m_genericSettings.getModelDirectories(), defaultDirectories)) { return empty; } return m_genericSettings.getModelDirectories(); } @@ -588,7 +588,7 @@ namespace BlackMisc case CSimulatorInfo::P3D: { if (CFsCommonUtil::p3dSimObjectsDir().isEmpty()) { return e; } - static const QStringList md({ CFsCommonUtil::p3dSimObjectsDir() }); + static const QStringList md = CFsCommonUtil::p3dSimObjectsDirPlusAddOnSimObjectsDirs(); return md; } case CSimulatorInfo::XPLANE: