mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-03-31 21:15:33 +08:00
* remove empty enries in directories * allow to add directory * detect same directories and avoid duplicates
284 lines
12 KiB
C++
284 lines
12 KiB
C++
/* Copyright (C) 2015
|
|
* swift Project Community / Contributors
|
|
*
|
|
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
|
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
|
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
|
* contained in the LICENSE file.
|
|
*/
|
|
|
|
#include "blackmisc/simulation/xplane/xplaneutil.h"
|
|
#include "blackmisc/fileutils.h"
|
|
#include "blackmisc/directoryutils.h"
|
|
#include "qsystemdetection.h"
|
|
#include <QDir>
|
|
#include <QFile>
|
|
#include <QFileInfo>
|
|
#include <QIODevice>
|
|
#include <QTextStream>
|
|
|
|
#if defined(Q_OS_WIN)
|
|
#include <Shlobj.h>
|
|
#endif
|
|
|
|
using namespace BlackMisc;
|
|
|
|
namespace BlackMisc
|
|
{
|
|
namespace Simulation
|
|
{
|
|
namespace XPlane
|
|
{
|
|
// Returns the last path from filePath, which does exist on the file system
|
|
QString getLastExistingPathFromFile(const QString &filePath)
|
|
{
|
|
const QFileInfo fileInfo(filePath);
|
|
if (!fileInfo.exists()) { return {}; }
|
|
QFile file(fileInfo.absoluteFilePath());
|
|
if (!file.open(QIODevice::ReadOnly))
|
|
{
|
|
return {};
|
|
}
|
|
|
|
QString lastLine;
|
|
QTextStream ts(&file);
|
|
while (!ts.atEnd())
|
|
{
|
|
QString pathToCheck = ts.readLine();
|
|
if (QFileInfo::exists(pathToCheck)) { lastLine = pathToCheck; }
|
|
}
|
|
return lastLine;
|
|
}
|
|
|
|
#if defined(Q_OS_WIN)
|
|
QString getWindowsLocalAppDataPath()
|
|
{
|
|
QString result;
|
|
TCHAR szLocalAppDataPath[MAX_PATH];
|
|
if (SUCCEEDED(SHGetFolderPath(NULL,
|
|
CSIDL_LOCAL_APPDATA,
|
|
NULL,
|
|
0,
|
|
szLocalAppDataPath)))
|
|
{
|
|
result = QString::fromWCharArray(szLocalAppDataPath);
|
|
}
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
QString CXPlaneUtil::xplane9Dir()
|
|
{
|
|
static const QString xplaneInstallFile("x-plane_install.txt");
|
|
const QString xplaneInstallFilePath = xplaneDir(xplaneInstallFile);
|
|
return getLastExistingPathFromFile(xplaneInstallFilePath);
|
|
}
|
|
|
|
QString CXPlaneUtil::xplane10Dir()
|
|
{
|
|
static const QString xplaneInstallFile("x-plane_install_10.txt");
|
|
const QString xplaneInstallFilePath = xplaneDir(xplaneInstallFile);
|
|
return getLastExistingPathFromFile(xplaneInstallFilePath);
|
|
}
|
|
|
|
QString CXPlaneUtil::xplane11Dir()
|
|
{
|
|
static const QString xplaneInstallFile("x-plane_install_11.txt");
|
|
const QString xplaneInstallFilePath = xplaneDir(xplaneInstallFile);
|
|
return getLastExistingPathFromFile(xplaneInstallFilePath);
|
|
}
|
|
|
|
QString CXPlaneUtil::xplaneDir(const QString &xplaneInstallFile)
|
|
{
|
|
//! \fixme KB 8/17 we could also use the runtime CBuildConfig decision here, which looks nicer (I personally always try to avoid ifdef)
|
|
#if defined(Q_OS_WIN)
|
|
return CFileUtils::appendFilePathsAndFixUnc(getWindowsLocalAppDataPath(), xplaneInstallFile);
|
|
#elif defined (Q_OS_LINUX)
|
|
static const QString xp(".x-plane");
|
|
return CFileUtils::appendFilePaths(QDir::homePath(), xp, xplaneInstallFile);
|
|
#elif defined (Q_OS_OSX)
|
|
static const QString lib("Library/Preferences");
|
|
return CFileUtils::appendFilePaths(QDir::homePath(), lib, xplaneInstallFile);
|
|
#endif
|
|
}
|
|
|
|
const QString &CXPlaneUtil::xplaneRootDir()
|
|
{
|
|
static const QString dir = []
|
|
{
|
|
if (!xplane11Dir().isEmpty()) { return xplane11Dir(); }
|
|
else if (!xplane10Dir().isEmpty()) { return xplane10Dir(); }
|
|
else if (!xplane9Dir().isEmpty()) { return xplane9Dir(); }
|
|
else { return QString(); }
|
|
}();
|
|
return dir;
|
|
}
|
|
|
|
bool CXPlaneUtil::isXplaneRootDirExisting()
|
|
{
|
|
static const bool exists = QDir(xplaneRootDir()).exists();
|
|
return exists;
|
|
}
|
|
|
|
const QString &CXPlaneUtil::xplanePluginDir()
|
|
{
|
|
static const QString pd(xplaneRootDir().isEmpty() ? "" : CFileUtils::appendFilePaths(xplaneRootDir(), xplanePluginPathName()));
|
|
return pd;
|
|
}
|
|
|
|
QString CXPlaneUtil::pluginDirFromRootDir(const QString &rootDir)
|
|
{
|
|
return CFileUtils::appendFilePathsAndFixUnc(rootDir, xplanePluginPathName());
|
|
}
|
|
|
|
QStringList CXPlaneUtil::modelDirectoriesFromSimDir(const QString &simulatorDir)
|
|
{
|
|
if (simulatorDir.isEmpty()) { return QStringList(); }
|
|
return QStringList({ simulatorDir });
|
|
}
|
|
|
|
const QString &CXPlaneUtil::xplanePluginPathName()
|
|
{
|
|
static const QString p("Resources/plugins");
|
|
return p;
|
|
}
|
|
|
|
const QString &CXPlaneUtil::xswiftbusPathName()
|
|
{
|
|
static const QString p("xswiftbus");
|
|
return p;
|
|
}
|
|
|
|
bool CXPlaneUtil::isXplanePluginDirDirExisting()
|
|
{
|
|
static const bool exists = QDir(xplanePluginDir()).exists();
|
|
return exists;
|
|
}
|
|
|
|
QStringList CXPlaneUtil::pluginSubdirectories(const QString &pluginDir)
|
|
{
|
|
const QString dirName = pluginDir.isEmpty() ? xplaneRootDir() : pluginDir;
|
|
if (!CDirectoryUtils::isDirExisting(dirName)) { return QStringList(); }
|
|
const QDir dir(dirName);
|
|
return dir.entryList(QDir::Dirs, QDir::Name | QDir::IgnoreCase);
|
|
}
|
|
|
|
const QStringList &CXPlaneUtil::xplaneModelDirectories()
|
|
{
|
|
static const QStringList dirs = xplaneRootDir().isEmpty() ? QStringList() : QStringList({ xplaneRootDir() });
|
|
return dirs;
|
|
}
|
|
|
|
const QStringList &CXPlaneUtil::xplaneModelExcludeDirectoryPatterns()
|
|
{
|
|
static const QStringList empty;
|
|
return empty;
|
|
}
|
|
|
|
QString CXPlaneUtil::xswiftbusPluginDir(const QString &xplaneRootDir)
|
|
{
|
|
const QString rootDir = xplaneRootDir.isEmpty() ? CXPlaneUtil::xplaneRootDir() : xplaneRootDir;
|
|
if (!rootDir.isEmpty())
|
|
{
|
|
const QString xswiftbusDir = CFileUtils::appendFilePathsAndFixUnc(CXPlaneUtil::pluginDirFromRootDir(xplaneRootDir), CXPlaneUtil::xswiftbusPathName());
|
|
if (CDirectoryUtils::isDirExisting(xswiftbusDir))
|
|
{
|
|
return xswiftbusDir;
|
|
}
|
|
}
|
|
return {};
|
|
}
|
|
|
|
QString CXPlaneUtil::xswiftbusLegacyDir(const QString &xplaneRootDir)
|
|
{
|
|
static const QString legacyPath("/Resources/plugins/xswiftbus/LegacyData");
|
|
// Return the first non empty path, we can find.
|
|
|
|
const QString rootDir = xplaneRootDir.isEmpty() ? CXPlaneUtil::xplaneRootDir() : xplaneRootDir;
|
|
if (!rootDir.isEmpty())
|
|
{
|
|
const QString xswiftbusLegacy = CFileUtils::appendFilePathsAndFixUnc(xplaneRootDir, legacyPath);
|
|
if (CDirectoryUtils::isDirExisting(xswiftbusLegacy))
|
|
{
|
|
return xswiftbusLegacy;
|
|
}
|
|
}
|
|
return {};
|
|
}
|
|
|
|
bool CXPlaneUtil::hasXSwiftBusBuildAndPluginDir(const QString &xplaneRootDir)
|
|
{
|
|
if (CDirectoryUtils::getXSwiftBusBuildDirectory().isEmpty()) { return false; }
|
|
const QString xswiftBusPluginDir = CXPlaneUtil::xswiftbusPluginDir(xplaneRootDir);
|
|
return (!xswiftBusPluginDir.isEmpty());
|
|
}
|
|
|
|
QStringList CXPlaneUtil::findConflictingPlugins(const QString &pluginDir)
|
|
{
|
|
const QStringList files = findAllXplFiles(pluginDir);
|
|
QStringList conflicts;
|
|
for (const QString &file : files)
|
|
{
|
|
if (file.contains("swift", Qt::CaseInsensitive)) { continue; }
|
|
if (file.contains("ivap", Qt::CaseInsensitive)) { conflicts.push_back(file); continue; }
|
|
if (file.contains("XSquawkBox", Qt::CaseInsensitive)) { conflicts.push_back(file); continue; }
|
|
}
|
|
return conflicts;
|
|
}
|
|
|
|
QStringList CXPlaneUtil::findAllXplFiles(const QString &pluginDir)
|
|
{
|
|
const QString dirName = CFileUtils::fixWindowsUncPath(pluginDir.isEmpty() ? xplaneRootDir() : pluginDir);
|
|
const QDir directory(dirName);
|
|
if (!directory.exists()) { return QStringList(); }
|
|
|
|
// this finds the current levels XPLs
|
|
QStringList files = directory.entryList(xplFileFilter(), QDir::Files, QDir::Name | QDir::IgnoreCase);
|
|
const QStringList dirs = directory.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name | QDir::IgnoreCase);
|
|
for (const QString &dir : dirs)
|
|
{
|
|
const QString subDir = CFileUtils::appendFilePaths(dirName, dir);
|
|
const QStringList subDirFiles = CXPlaneUtil::findAllXplFiles(subDir);
|
|
if (subDirFiles.isEmpty()) { continue; }
|
|
for (const QString &file : subDirFiles)
|
|
{
|
|
files.push_back(CFileUtils::appendFilePaths(dir, file));
|
|
}
|
|
}
|
|
return files;
|
|
}
|
|
|
|
bool CXPlaneUtil::hasNewerXSwiftBusBuild(const QString &xplaneRootDir)
|
|
{
|
|
if (CDirectoryUtils::getXSwiftBusBuildDirectory().isEmpty()) { return false; }
|
|
const QString xswiftBusPluginDir = CXPlaneUtil::xswiftbusPluginDir(xplaneRootDir);
|
|
if (xswiftBusPluginDir.isEmpty()) { return false; }
|
|
|
|
const QFileInfo fiLatestBuild = CFileUtils::findLastModified(CDirectoryUtils::getXSwiftBusBuildDirectory(), true, xplFileFilter());
|
|
if (!fiLatestBuild.lastModified().isValid()) { return false; }
|
|
|
|
const QFileInfo fiLatestDeployed = CFileUtils::findLastModified(xswiftBusPluginDir, true, xplFileFilter());
|
|
if (!fiLatestDeployed.lastModified().isValid()) { return true; } // not yet existing
|
|
|
|
// newer?
|
|
return fiLatestBuild.lastModified() > fiLatestDeployed.lastModified();
|
|
}
|
|
|
|
int CXPlaneUtil::copyXSwiftBusBuildFiles(const QString &xplaneRootDir)
|
|
{
|
|
if (CDirectoryUtils::getXSwiftBusBuildDirectory().isEmpty()) { return -1; }
|
|
const QString xswiftBusPluginDir = CXPlaneUtil::xswiftbusPluginDir(xplaneRootDir);
|
|
if (xswiftBusPluginDir.isEmpty()) { return -1; }
|
|
|
|
return CDirectoryUtils::copyDirectoryRecursively(CDirectoryUtils::getXSwiftBusBuildDirectory(), xswiftBusPluginDir, true);
|
|
}
|
|
|
|
const QStringList &CXPlaneUtil::xplFileFilter()
|
|
{
|
|
static const QStringList filter({"*.xpl"});
|
|
return filter;
|
|
}
|
|
} // namespace
|
|
} // namespace
|
|
} // namespace
|