diff --git a/src/blackmisc/fileutils.cpp b/src/blackmisc/fileutils.cpp index da87dd0c9..6ae812ecc 100644 --- a/src/blackmisc/fileutils.cpp +++ b/src/blackmisc/fileutils.cpp @@ -150,6 +150,13 @@ namespace BlackMisc CFileUtils::appendFilePaths(CFileUtils::appendFilePaths(path1, path2), path3); } + QString CFileUtils::pathUp(const QString &path) + { + const int i = path.lastIndexOf('/'); + if (i < 0) { return path; } + return path.left(i); + } + QString CFileUtils::normalizeFilePathToQtStandard(const QString &filePath) { if (filePath.isEmpty()) { return ""; } diff --git a/src/blackmisc/fileutils.h b/src/blackmisc/fileutils.h index 75f627060..6e08b72c7 100644 --- a/src/blackmisc/fileutils.h +++ b/src/blackmisc/fileutils.h @@ -79,6 +79,9 @@ namespace BlackMisc //! \sa CNetworkUtils::buildUrl for URLs static QString appendFilePathsAndFixUnc(const QString &path1, const QString &path2, const QString &path3); + //! One path up + static QString pathUp(const QString &path); + //! Strip file from path a/b/c.json a/b, return path static QString stripFileFromPath(const QString &path); diff --git a/src/blackmisc/simulation/fscommon/fscommonutil.cpp b/src/blackmisc/simulation/fscommon/fscommonutil.cpp index 4d2ddfe9a..60b139357 100644 --- a/src/blackmisc/simulation/fscommon/fscommonutil.cpp +++ b/src/blackmisc/simulation/fscommon/fscommonutil.cpp @@ -10,23 +10,22 @@ #include "blackmisc/simulation/fscommon/fscommonutil.h" #include "blackmisc/directoryutils.h" #include "blackmisc/fileutils.h" +#include "blackmisc/stringutils.h" #include "blackconfig/buildconfig.h" #include #include #include +#include #include #include #include #include +#include +#include #include using namespace BlackConfig; -using namespace BlackMisc; - -// -// all FSX/P3D keys: http://www.fsdeveloper.com/forum/threads/registry-keys-fsx-fsx-se-p3dv1-p3dv2.432633/ -// namespace BlackMisc { @@ -386,6 +385,123 @@ namespace BlackMisc messages.push_back(CStatusMessage(cats, CStatusMessage::SeverityInfo, QString("Copied %1 files from '%2' to '%3'").arg(copied).arg(CDirectoryUtils::shareTerrainProbeDirectory(), targetDir))); return copied; } + + QSet CFsCommonUtil::findP3dAddOnConfigFiles(const QString &versionHint) + { + const QStringList locations = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation); + QSet files; + for (const QString &path : locations) + { + QString pathUp = CFileUtils::appendFilePaths(CFileUtils::pathUp(path), "Lockheed Martin"); + const QDir d(pathUp); + if (!d.exists()) { continue; } + + // all version sub directories + // looking for "add-ons.cfg" + static const QString cfgFile("add-ons.cfg"); + const QStringList entries = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot); + for (const QString &entry : entries) + { + if (entry.contains(versionHint, Qt::CaseInsensitive)) + { + const QString f = CFileUtils::appendFilePaths(d.absolutePath(), entry, cfgFile); + const QFileInfo fi(f); + if (fi.exists()) { files.insert(f); } + } + } + } + return files; + } + + QSet CFsCommonUtil::allP3dAddOnPaths(const QStringList &addOnConfigsFiles, bool checked) + { + if (addOnConfigsFiles.isEmpty()) { return QSet(); } + QSet paths; + for (const QString &configFile : addOnConfigsFiles) + { + // manually parsing because QSettings did not work properly + const QString fileContent = CFileUtils::readFileToString(configFile); + if (fileContent.isEmpty()) { continue; } + const QList lines = splitLinesRefs(fileContent); + static const QString p("PATH="); + for (const QStringRef &line : lines) + { + const int i = line.lastIndexOf(p, Qt::CaseInsensitive); + if (i < 0 || line.endsWith('=')) { continue; } + const QStringRef path = line.mid(i + p.length()); + const QDir dir(QDir::fromNativeSeparators(path.toString())); + if (!checked || dir.exists()) { paths.insert(dir.absolutePath()); } + } + } + return paths; + } + + QSet CFsCommonUtil::allP3dAddOnSimObjectPaths(const QStringList &addOnPaths, bool checked) + { + if (addOnPaths.isEmpty()) { return QSet(); } + 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()); } + } + return simObjectPaths; + } + + QStringList CFsCommonUtil::findFsxConfigFiles() + { + const QStringList locations = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation); + QStringList files; + for (const QString &path : locations) + { + QString file = CFileUtils::appendFilePaths(CFileUtils::pathUp(path), "Microsoft/FSX/fsx.cfg"); + const QFileInfo fi(file); + if (fi.exists()) { files.push_back(fi.absoluteFilePath()); } + } + return files; + } + + QSet CFsCommonUtil::fsxSimObjectsPaths(const QStringList &fsxFiles, bool checked) + { + QSet paths; + for (const QString &fsxFile : fsxFiles) + { + paths.unite(fsxSimObjectsPaths(fsxFile, checked)); + } + return paths; + } + + QSet CFsCommonUtil::fsxSimObjectsPaths(const QString &fsxFile, bool checked) + { + const QString fileContent = CFileUtils::readFileToString(fsxFile); + if (fileContent.isEmpty()) { return QSet(); } + const QList lines = splitLinesRefs(fileContent); + static const QString p("SimObjectPaths."); + + QSet paths; + for (const QStringRef &line : lines) + { + const int i1 = line.lastIndexOf(p, Qt::CaseInsensitive); + if (i1 < 0) { continue; } + const int i2 = line.lastIndexOf('='); + if (i2 < 0 || i1 >= i2 || line.endsWith('=')) { continue; } + const QStringRef path = line.mid(i2 + 1); + const QString soPath = QDir::fromNativeSeparators(path.toString()); + const QFileInfo fi(soPath); + + // relative or absolute paths + if (fi.isAbsolute() && (!checked || fi.exists())) + { + paths.insert(fi.absolutePath()); + } + else + { + paths.insert(soPath); + } + } + return paths; + } } // namespace } // namespace } // namespace diff --git a/src/blackmisc/simulation/fscommon/fscommonutil.h b/src/blackmisc/simulation/fscommon/fscommonutil.h index 57ce0bf85..dfb1c703b 100644 --- a/src/blackmisc/simulation/fscommon/fscommonutil.h +++ b/src/blackmisc/simulation/fscommon/fscommonutil.h @@ -14,9 +14,8 @@ #include "blackmisc/simulation/aircraftmodel.h" #include "blackmisc/blackmiscexport.h" -#include - -class QStringList; +#include +#include namespace BlackMisc { @@ -24,7 +23,7 @@ namespace BlackMisc { namespace FsCommon { - //! FS9/X/P3D utils + //! FS9/FSX/P3D utils class BLACKMISC_EXPORT CFsCommonUtil { public: @@ -93,6 +92,29 @@ namespace BlackMisc //! Copy the terrain probe static int copyFsxTerrainProbeFiles(const QString &simObjectDir, CStatusMessageList &messages); + + //! Find the config files + //! \note C:/Users/Joe Doe/AppData/Roaming/Lockheed Martin/Prepar3D v4 + //! \param versionHint like "v4" + static QSet findP3dAddOnConfigFiles(const QString &versionHint); + + //! All add-on paths from the config files + static QSet allP3dAddOnPaths(const QStringList &addOnConfigsFiles, bool checked); + + //! All add-on paths from the config files + static QSet allP3dAddOnSimObjectPaths(const QStringList &addOnPaths, bool checked); + + //! Find the config files + // C:/Users/Joe Doe/AppData/Roaming/Lockheed Martin/Prepar3D v4 + static QStringList findFsxConfigFiles(); + + //! Get all the SimObjects files from fsx.cfg + // SimObjectPaths.0=SimObjects\Airplanes + static QSet fsxSimObjectsPaths(const QStringList &fsxFiles, bool checked); + + //! Get all the SimObjects files from fsx.cfg + // SimObjectPaths.0=SimObjects\Airplanes + static QSet fsxSimObjectsPaths(const QString &fsxFile, bool checked); }; } // namespace } // namespace diff --git a/src/blackmisc/stringutils.cpp b/src/blackmisc/stringutils.cpp index d5b78ba0e..c850f3e09 100644 --- a/src/blackmisc/stringutils.cpp +++ b/src/blackmisc/stringutils.cpp @@ -404,6 +404,12 @@ namespace BlackMisc } return ci; } + + QString joinStringSet(const QSet &set, const QString &separator) + { + if (set.isEmpty()) { return QStringLiteral(""); } + return set.toList().join(separator); + } } // ns //! \endcond diff --git a/src/blackmisc/stringutils.h b/src/blackmisc/stringutils.h index 5dfa87f8d..631eb62c5 100644 --- a/src/blackmisc/stringutils.h +++ b/src/blackmisc/stringutils.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -252,6 +253,9 @@ namespace BlackMisc //! \remark TZ is UTC BLACKMISC_EXPORT QDateTime parseDateTimeStringOptimized(const QString &dateTimeString); + //! Convert string to bool + BLACKMISC_EXPORT QString joinStringSet(const QSet &set, const QString &separator); + namespace Mixin { /*!