f648cb1fd8
* Update the FileIOAlias naming to make the cache, project root and engine root paths more clear The alias of `@root@`, `@assets@`, and `@projectplatformcache@` has been collapsed to `@projectproductassets@` The alias of `@devroot@` and `@engroot@` has been collapsed to `@engroot@` The alias of `@devassets@` and `@projectroot@` has been collapsed to `@projectroot@` Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated use of devassets and devroot properties in python Those properties now use projectroot and engroot Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updating the alias @engroot@ alias path comment in each platform specific LocalFileIO_*.cpp file Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed hardcoded size of 9 for the product asset alias. The ResolvePath function now just appends the @projectproductassets@ alias with the input path Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Remove duplicate @projectproductassets@ check in ProcessFileTreeRequest Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fix for typos in Hydra python test Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated LocalFileIO::Copy call on Windows to use the Unicode aware CopyFileW API Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the AWSMetreicsGemAllocatorFixture to properly suppress asset cache write errors for Test file creation. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed unneeded call to set the @projectproductasstes@ alias at the bottom of the AssetSeedManagerTest SetUp Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Added a deprecated alias map to the FileIO System When a deprecated alias is accessed, the FileIO System logs an AZ_Error and indicates the alias that should be used Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated python test scripts to use the projectroot binding Retrieving the AutomatedTesting project path based on "<devroot>/AutomatedTesting" has been removed. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated references to devroot and devgame within the codebase The GetAbsoluteDevGameFolderPath functions has been replaced with direct call to AZ::Utils::GetProjectPath The GetAbsoluteDevRootFolderPath functions has been replaced with direct calls to AZ::Utils::GetEnginePath Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated <engroot>/AutomatedTesting references to projectroot Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Replaced references that assumes the project path is <engroot>/AutomatedTesting with <projectroot> in the AutomatedTesting python test Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Correct casing in emfxworkspace file Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed newly added AppendPathParts function Removed the Path constructors which accepts a PathIterable instance The PathIterable isn't safe to return to a user of the Path class as it might be referencing temporary paths supplied via PathView arguments Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fixed unused parameter warning Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Undid change to the LexicallyProximate function to set the path result to the base path. It needs to return the *this path if the pathResult is empty Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Moved the LocalFileIO ConvertToAbsolutePath implementations to AZ::Utils Fixed the ConvertToAbsolutePath implementation for Unix platforms to use a buffer that is size PATH_MAX(4096 on all our supported Unix platforms). Because the buffer before was AZ::IO::MaxPathLength which as a size of 1024, this was resulting in the Unix `realpath` function smashing the stack when it converts a path to an absolute path that is longer than 1024 characters Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the EditorCore.Tests to attach the AZ Environment to the EditorCore shared library that is statically loaded on launch. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fixed for DeprecatedAlaisesKeyVisitor Visit function causing the non string_view overloads being hidden causing a hidden base class function warning Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Changed the AWSMetricsGemMock to use a temporary for writing test assets Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the LocalFileIO::ResolvePath function to use HasRootPath to determine if a path starts with a root path such as "D:", "D:/" or "/" IsAbsolute was not the corect check as the path of "D:" is a relative path. To be absolute according to the Windows the path must have a root directory. i.e "D:/" or "D:\" Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed absolute path comment from LocalFile_UnixLike.cpp and LocalFile_Android.cpp FindFiles implementations Updated the ConvertToAlias to supply an AZ::IO::FixedMaxPath Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Replaced usage of the @projectproductassets@ alias with @engroot@ when referring to the LmbrCentral source folder in the CopyDependencyBuilderTest and the SeedBuilderTests Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the ScriptCanvas Upgrade Tool to output backed up files to the Project User Path instead of the engine root Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fixed whitespacing issues in Application.cpp Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Remove unnecessary creation of a FixedMaxPath in the UpgradeTool.cpp Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Modified testSeedFolder variable in the SeedBuilderTests to use the @engroot@ alias instead of @projectproductassets@/.. alias when referring to the LmbrCentral Gem source path Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated references to the Project Asset Cache in the PythonTests. Those tests no longer use the logic `azlmbr.paths.projectroot / "Cache" / "pc"` to retrieve a path to the cache root but instead the `azlmbr.paths.projectproductassets` constant Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fixed the FileIO Deprecated Alias test on Windows Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removing @projectsourceassets@ alias, as it is only used once. Updated the PhysX EditorSystemComponent.cpp to query the ProjectPath form the SettingsRegistry. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Replaced @projectproductassets@ alias with @products@ Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Rollback changes to the PhysX EditorSystemComponent.cpp The changes to use the ProjectPath from the SettingsRegistry has been implemented in PR #4497 Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>
418 lines
14 KiB
C++
418 lines
14 KiB
C++
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
*
|
|
*/
|
|
|
|
|
|
#include "EditorDefs.h"
|
|
|
|
#include "PathUtil.h"
|
|
|
|
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
|
#include <AzCore/Utils/Utils.h>
|
|
#include <AzToolsFramework/API/EditorAssetSystemAPI.h> // for ebus events
|
|
#include <AzFramework/API/ApplicationAPI.h>
|
|
#include <AzCore/std/string/conversions.h>
|
|
#include <AzFramework/IO/LocalFileIO.h>
|
|
|
|
#include <QRegularExpression>
|
|
|
|
namespace Path
|
|
{
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void SplitPath(const QString& rstrFullPathFilename, QString& rstrDriveLetter, QString& rstrDirectory, QString& rstrFilename, QString& rstrExtension)
|
|
{
|
|
AZStd::string strFullPathString(rstrFullPathFilename.toUtf8().data());
|
|
AZStd::string strDriveLetter;
|
|
AZStd::string strDirectory;
|
|
AZStd::string strFilename;
|
|
AZStd::string strExtension;
|
|
|
|
char* szPath((char*)strFullPathString.c_str());
|
|
char* pchLastPosition(szPath);
|
|
char* pchCurrentPosition(szPath);
|
|
char* pchAuxPosition(szPath);
|
|
|
|
// Directory named filenames containing ":" are invalid, so we can assume if there is a :
|
|
// it will be the drive name.
|
|
pchCurrentPosition = strchr(pchLastPosition, ':');
|
|
if (pchCurrentPosition == nullptr)
|
|
{
|
|
rstrDriveLetter = "";
|
|
}
|
|
else
|
|
{
|
|
strDriveLetter.assign(pchLastPosition, pchCurrentPosition + 1);
|
|
pchLastPosition = pchCurrentPosition + 1;
|
|
}
|
|
|
|
pchCurrentPosition = strrchr(pchLastPosition, '\\');
|
|
pchAuxPosition = strrchr(pchLastPosition, '/');
|
|
if ((pchCurrentPosition == nullptr) && (pchAuxPosition == nullptr))
|
|
{
|
|
rstrDirectory = "";
|
|
}
|
|
else
|
|
{
|
|
// Since NULL is < valid pointer, so this will work.
|
|
if (pchAuxPosition > pchCurrentPosition)
|
|
{
|
|
pchCurrentPosition = pchAuxPosition;
|
|
}
|
|
strDirectory.assign(pchLastPosition, pchCurrentPosition + 1);
|
|
pchLastPosition = pchCurrentPosition + 1;
|
|
}
|
|
|
|
pchCurrentPosition = strrchr(pchLastPosition, '.');
|
|
if (pchCurrentPosition == nullptr)
|
|
{
|
|
rstrExtension = "";
|
|
strFilename.assign(pchLastPosition);
|
|
}
|
|
else
|
|
{
|
|
strExtension.assign(pchCurrentPosition);
|
|
strFilename.assign(pchLastPosition, pchCurrentPosition);
|
|
}
|
|
|
|
rstrDriveLetter = strDriveLetter.c_str();
|
|
rstrDirectory = strDirectory.c_str();
|
|
rstrFilename = strFilename.c_str();
|
|
rstrExtension = strExtension.c_str();
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void GetDirectoryQueue(const QString& rstrSourceDirectory, QStringList& rcstrDirectoryTree)
|
|
{
|
|
AZStd::string strCurrentDirectoryName;
|
|
AZStd::string strSourceDirectory(rstrSourceDirectory.toUtf8().data());
|
|
const char* szSourceDirectory(strSourceDirectory.c_str());
|
|
const char* pchCurrentPosition(szSourceDirectory);
|
|
const char* pchLastPosition(szSourceDirectory);
|
|
|
|
rcstrDirectoryTree.clear();
|
|
|
|
if (strSourceDirectory.empty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// It removes as many slashes the path has in its start...
|
|
// MAYBE and just maybe we should consider paths starting with
|
|
// more than 2 slashes invalid paths...
|
|
while ((*pchLastPosition == '\\') || (*pchLastPosition == '/'))
|
|
{
|
|
++pchLastPosition;
|
|
++pchCurrentPosition;
|
|
}
|
|
|
|
do
|
|
{
|
|
pchCurrentPosition = strpbrk(pchLastPosition, "\\/");
|
|
if (pchCurrentPosition == nullptr)
|
|
{
|
|
break;
|
|
}
|
|
strCurrentDirectoryName.assign(pchLastPosition, pchCurrentPosition);
|
|
pchLastPosition = pchCurrentPosition + 1;
|
|
// Again, here we are skipping as many consecutive slashes.
|
|
while ((*pchLastPosition == '\\') || (*pchLastPosition == '/'))
|
|
{
|
|
++pchLastPosition;
|
|
}
|
|
|
|
|
|
rcstrDirectoryTree.push_back(strCurrentDirectoryName.c_str());
|
|
} while (true);
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void ConvertSlashToBackSlash(QString& rstrStringToConvert)
|
|
{
|
|
rstrStringToConvert.replace('/', '\\');
|
|
rstrStringToConvert = CaselessPaths(rstrStringToConvert);
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void ConvertBackSlashToSlash(QString& rstrStringToConvert)
|
|
{
|
|
rstrStringToConvert.replace('\\', '/');
|
|
rstrStringToConvert = CaselessPaths(rstrStringToConvert);
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void SurroundWithQuotes(QString& rstrSurroundString)
|
|
{
|
|
QString strSurroundString(rstrSurroundString);
|
|
|
|
if (!strSurroundString.isEmpty())
|
|
{
|
|
if (strSurroundString[0] != '\"')
|
|
{
|
|
strSurroundString.insert(0, "\"");
|
|
}
|
|
if (strSurroundString[strSurroundString.size() - 1] != '\"')
|
|
{
|
|
strSurroundString.insert(strSurroundString.size(), "\"");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
strSurroundString.insert(0, "\"");
|
|
strSurroundString.insert(strSurroundString.size(), "\"");
|
|
}
|
|
rstrSurroundString = strSurroundString;
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
QString GetExecutableFullPath()
|
|
{
|
|
return QDir::toNativeSeparators(QCoreApplication::applicationFilePath());
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
QString GetWindowsTempDirectory()
|
|
{
|
|
return QDir::tempPath();
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
QString GetEngineRootPath()
|
|
{
|
|
const char* engineRoot;
|
|
EBUS_EVENT_RESULT(engineRoot, AzFramework::ApplicationRequests::Bus, GetEngineRoot);
|
|
return QString(engineRoot);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
QString& ReplaceFilename(const QString& strFilepath, const QString& strFilename, QString& strOutputFilename, bool bCallCaselessPath)
|
|
{
|
|
QString strDriveLetter;
|
|
QString strDirectory;
|
|
QString strOriginalFilename;
|
|
QString strExtension;
|
|
|
|
SplitPath(strFilepath, strDriveLetter, strDirectory, strOriginalFilename, strExtension);
|
|
|
|
strOutputFilename = strDriveLetter;
|
|
strOutputFilename += strDirectory;
|
|
strOutputFilename += strFilename;
|
|
strOutputFilename += strExtension;
|
|
|
|
if (bCallCaselessPath)
|
|
{
|
|
strOutputFilename = CaselessPaths(strOutputFilename);
|
|
}
|
|
return strOutputFilename;
|
|
}
|
|
|
|
bool IsFolder(const char* pPath)
|
|
{
|
|
return AZ::IO::FileIOBase::GetInstance()->IsDirectory(pPath);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
QString GetUserSandboxFolder()
|
|
{
|
|
return QString::fromUtf8("@user@/Sandbox/");
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
QString GetResolvedUserSandboxFolder()
|
|
{
|
|
AZ::IO::FixedMaxPath userSandboxFolderPath;
|
|
gEnv->pFileIO->ResolvePath(userSandboxFolderPath, GetUserSandboxFolder().toUtf8().constData());
|
|
return QString::fromUtf8(userSandboxFolderPath.c_str(), static_cast<int>(userSandboxFolderPath.Native().size()));
|
|
}
|
|
|
|
// internal function, you should use GetEditingGameDataFolder instead.
|
|
AZStd::string GetGameAssetsFolder()
|
|
{
|
|
AZ::IO::Path projectPath;
|
|
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
|
|
{
|
|
settingsRegistry->Get(projectPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath);
|
|
}
|
|
|
|
return projectPath.Native();
|
|
}
|
|
|
|
/// Get the data folder
|
|
AZStd::string GetEditingGameDataFolder()
|
|
{
|
|
// Define here the mod name
|
|
static AZ::IO::FixedMaxPathString s_currentModName;
|
|
|
|
if (s_currentModName.empty())
|
|
{
|
|
return GetGameAssetsFolder();
|
|
}
|
|
AZStd::string str(GetGameAssetsFolder());
|
|
str += "Mods\\";
|
|
str += s_currentModName.c_str();
|
|
return str;
|
|
}
|
|
|
|
|
|
AZStd::string MakeModPathFromGamePath(const char* relGamePath)
|
|
{
|
|
return GetEditingGameDataFolder() + "\\" + relGamePath;
|
|
}
|
|
|
|
QString FullPathToLevelPath(const QString& path)
|
|
{
|
|
if (path.isEmpty())
|
|
{
|
|
return "";
|
|
}
|
|
|
|
QString relGamePath;
|
|
|
|
if (!QFileInfo(path).isRelative())
|
|
{
|
|
relGamePath = GetRelativePath(path);
|
|
}
|
|
else
|
|
{
|
|
relGamePath = path;
|
|
}
|
|
|
|
QString levelpath = GetIEditor()->GetLevelFolder();
|
|
QString str = levelpath;
|
|
str.replace('/', '\\');
|
|
levelpath = CaselessPaths(str);
|
|
|
|
// Create relative path
|
|
QString relLevelPath = QDir(levelpath).relativeFilePath(relGamePath);
|
|
if (relLevelPath.isEmpty())
|
|
{
|
|
assert(0);
|
|
return path;
|
|
}
|
|
|
|
relLevelPath.remove(QRegularExpression(QStringLiteral(R"(^[\\/.]*)")));
|
|
return relLevelPath;
|
|
}
|
|
|
|
QString Make(const QString& path, const QString& file)
|
|
{
|
|
if (gEnv->pCryPak->IsAbsPath(file.toUtf8().data()))
|
|
{
|
|
return file;
|
|
}
|
|
return CaselessPaths(AddPathSlash(path) + file);
|
|
}
|
|
|
|
QString GetRelativePath(const QString& fullPath, bool bRelativeToGameFolder /*= false*/)
|
|
{
|
|
if (fullPath.isEmpty())
|
|
{
|
|
return "";
|
|
}
|
|
|
|
bool relPathFound = false;
|
|
AZStd::string relativePath;
|
|
AZStd::string fullAssetPath(fullPath.toUtf8().data());
|
|
EBUS_EVENT_RESULT(relPathFound, AzToolsFramework::AssetSystemRequestBus, GetRelativeProductPathFromFullSourceOrProductPath, fullAssetPath, relativePath);
|
|
|
|
if (relPathFound)
|
|
{
|
|
// do not normalize this path, it will already be an appropriate asset ID.
|
|
return CaselessPaths(relativePath.c_str());
|
|
}
|
|
|
|
AZ::IO::FixedMaxPath rootPath = bRelativeToGameFolder ? AZ::Utils::GetProjectPath() : AZ::Utils::GetEnginePath();
|
|
AZ::IO::FixedMaxPath resolvedFullPath;
|
|
AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(resolvedFullPath, fullPath.toUtf8().constData());
|
|
|
|
// Create relative path
|
|
|
|
return CaselessPaths(resolvedFullPath.LexicallyProximate(rootPath).MakePreferred().c_str());
|
|
}
|
|
|
|
QString GamePathToFullPath(const QString& path)
|
|
{
|
|
using namespace AzToolsFramework;
|
|
AZ_Warning("GamePathToFullPath", path.size() <= AZ::IO::MaxPathLength, "Path exceeds maximum path length of %zu", AZ::IO::MaxPathLength);
|
|
if (path.size() <= AZ::IO::MaxPathLength)
|
|
{
|
|
// first, adjust the file name for mods:
|
|
bool fullPathFound = false;
|
|
AZ::IO::Path assetFullPath;
|
|
AZ::IO::Path adjustedFilePath = path.toUtf8().constData();
|
|
AssetSystemRequestBus::BroadcastResult(fullPathFound, &AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath,
|
|
adjustedFilePath.Native(), assetFullPath.Native());
|
|
if (fullPathFound)
|
|
{
|
|
//if the bus message succeeds than normalize
|
|
return assetFullPath.LexicallyNormal().c_str();
|
|
}
|
|
// if the bus message didn't succeed, check if he path exist as a resolved path
|
|
else
|
|
{
|
|
// Not all systems have been converted to use local paths. Some editor files save XML files directly, and a full or correctly aliased path is already passed in.
|
|
// If the path passed in exists already, then return the resolved filepath
|
|
if (AZ::IO::FileIOBase::GetDirectInstance()->Exists(adjustedFilePath.c_str()))
|
|
{
|
|
AZ::IO::FixedMaxPath resolvedPath;
|
|
AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(resolvedPath, adjustedFilePath);
|
|
return QString::fromUtf8(resolvedPath.c_str(), static_cast<int>(resolvedPath.Native().size()));
|
|
}
|
|
return path;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return QString{};
|
|
}
|
|
}
|
|
|
|
QString ToUnixPath(const QString& strPath, bool bCallCaselessPath)
|
|
{
|
|
QString str = strPath;
|
|
str.replace('\\', '/');
|
|
return bCallCaselessPath ? CaselessPaths(str) : str;
|
|
}
|
|
|
|
QString RemoveBackslash(QString path)
|
|
{
|
|
if (path.isEmpty())
|
|
{
|
|
return path;
|
|
}
|
|
|
|
int iLenMinus1 = path.length() - 1;
|
|
QChar cLastChar = path[iLenMinus1];
|
|
|
|
if (cLastChar == '\\' || cLastChar == '/')
|
|
{
|
|
return CaselessPaths(path.mid(0, iLenMinus1));
|
|
}
|
|
|
|
return CaselessPaths(path);
|
|
}
|
|
|
|
QString SubDirectoryCaseInsensitive(const QString& path, const QStringList& parts)
|
|
{
|
|
if (parts.isEmpty())
|
|
{
|
|
return path;
|
|
}
|
|
|
|
QStringList modifiedParts = parts;
|
|
auto currentPart = modifiedParts.takeFirst();
|
|
|
|
// case insensitive iterator
|
|
QDirIterator it(path);
|
|
while (it.hasNext())
|
|
{
|
|
it.next();
|
|
// the current part already exists, use it, case doesn't matter
|
|
auto actualName = it.fileName();
|
|
if (QString::compare(actualName, currentPart, Qt::CaseInsensitive) == 0)
|
|
{
|
|
return SubDirectoryCaseInsensitive(QDir(path).absoluteFilePath(actualName), modifiedParts);
|
|
}
|
|
}
|
|
// the current path doesn't exist yet, so just create the complete path in one rush
|
|
return QDir(path).absoluteFilePath(parts.join('/'));
|
|
}
|
|
}
|
|
|