You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
812 lines
28 KiB
C++
812 lines
28 KiB
C++
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
*
|
|
*/
|
|
#include "EditorDefs.h"
|
|
|
|
#include "AssetImporterManager.h"
|
|
|
|
// Qt
|
|
#include <QFileDialog>
|
|
#include <QMessageBox>
|
|
#include <QSettings>
|
|
#include <QStandardPaths>
|
|
|
|
// AzFramework
|
|
#include <AzFramework/Asset/AssetSystemBus.h>
|
|
|
|
// AzToolsFramework
|
|
#include <AzToolsFramework/UI/UICore/WidgetHelpers.h>
|
|
|
|
// Editor
|
|
#include "AssetImporter/UI/FilesAlreadyExistDialog.h"
|
|
#include "AssetImporter/UI/ProcessingAssetsDialog.h"
|
|
|
|
namespace AssetImporterManagerPrivate
|
|
{
|
|
const char* g_selectFilesPath = "AssetImporter/SelectFilesPath";
|
|
const char* g_selectDestinationFilesPath = "AssetImporter/SelectDestinationFilesPath";
|
|
const char* g_errorMessageBoxTitle = "File failed to process.";
|
|
const char* g_crateError = "Crate files cannot be imported.";
|
|
static const char* s_crateFileExtension = "crate";
|
|
};
|
|
|
|
AssetImporterManager::AssetImporterManager(QWidget* parent)
|
|
: QObject(parent)
|
|
{
|
|
}
|
|
|
|
AssetImporterManager::~AssetImporterManager()
|
|
{
|
|
}
|
|
|
|
void AssetImporterManager::Exec()
|
|
{
|
|
// tell the AssetImporterDragAndDropHandler that the Asset Importer now is running
|
|
Q_EMIT StartAssetImporter();
|
|
bool success = OnBrowseFiles();
|
|
|
|
// prevent users from selecting crate files from the File Explorer and open the Asset Importer.
|
|
if (!success)
|
|
{
|
|
reject();
|
|
}
|
|
else
|
|
{
|
|
OnOpenSelectDestinationDialog();
|
|
}
|
|
}
|
|
|
|
void AssetImporterManager::Exec(const QStringList& dragAndDropFileList)
|
|
{
|
|
// note: dragging and dropping an empty folder can also trigger this condition
|
|
if (!dragAndDropFileList.isEmpty())
|
|
{
|
|
OnDragAndDropFiles(&dragAndDropFileList);
|
|
|
|
// only open the Asset Importer when the folder contains correct type files
|
|
if (!m_pathMap.isEmpty())
|
|
{
|
|
// tell the AssetImporterDragAndDropHandler that the Asset Importer now is running
|
|
Q_EMIT StartAssetImporter();
|
|
OnOpenSelectDestinationDialog();
|
|
}
|
|
else
|
|
{
|
|
reject();
|
|
}
|
|
}
|
|
}
|
|
|
|
// used to cancel actions and close the dialog
|
|
void AssetImporterManager::reject()
|
|
{
|
|
m_pathMap.clear();
|
|
m_destinationRootDirectory = "";
|
|
Q_EMIT StopAssetImporter();
|
|
}
|
|
|
|
void AssetImporterManager::OnDragAndDropFiles(const QStringList* fileList)
|
|
{
|
|
for (int i = 0; i < fileList->size(); ++i)
|
|
{
|
|
// if the list contains a crate file,
|
|
// the whole process should stop
|
|
if (!GetAndCheckAllFilesInFolder(fileList->at(i)))
|
|
{
|
|
QMessageBox::warning(AzToolsFramework::GetActiveWindow(), AssetImporterManagerPrivate::g_errorMessageBoxTitle, AssetImporterManagerPrivate::g_crateError);
|
|
reject();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool AssetImporterManager::OnBrowseFiles()
|
|
{
|
|
QFileDialog fileDialog;
|
|
fileDialog.setFileMode(QFileDialog::ExistingFiles);
|
|
fileDialog.setWindowModality(Qt::WindowModality::ApplicationModal);
|
|
fileDialog.setViewMode(QFileDialog::Detail);
|
|
fileDialog.setWindowTitle(tr("Select files to import"));
|
|
fileDialog.setLabelText(QFileDialog::Accept, "Select");
|
|
|
|
QSettings settings;
|
|
QString currentAbsolutePath = settings.value(AssetImporterManagerPrivate::g_selectFilesPath).toString();
|
|
|
|
QDir gameRoot(Path::GetEditingGameDataFolder().c_str());
|
|
QString gameRootAbsPath = gameRoot.absolutePath();
|
|
|
|
// Case 1: if currentAbsolutePath is empty at this point, that means this is the first time
|
|
// users using the Asset Importer, set the default directory to be users' PC's desktop.
|
|
// Case 2: if the current folder directory stored in the registry doesn't exist anymore,
|
|
// that means users have removed the directory already (deleted or use the Move feature).
|
|
// Case 3: if it's a directory under the game root folder, then in general,
|
|
// users have modified the folder directory in the registry. It should not be happening.
|
|
if (currentAbsolutePath.isEmpty() || !QFile(currentAbsolutePath).exists() || currentAbsolutePath.startsWith(gameRootAbsPath, Qt::CaseInsensitive))
|
|
{
|
|
currentAbsolutePath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
|
}
|
|
|
|
fileDialog.setDirectory(currentAbsolutePath);
|
|
|
|
if (!fileDialog.exec())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool encounteredCrate = false;
|
|
QStringList invalidFiles;
|
|
|
|
for (QString path : fileDialog.selectedFiles())
|
|
{
|
|
QString fileName = GetFileName(path);
|
|
QFileInfo info(path);
|
|
QString extension = info.completeSuffix(); // extension without '.'
|
|
|
|
if (QString(AssetImporterManagerPrivate::s_crateFileExtension).compare(extension, Qt::CaseInsensitive) != 0)
|
|
{
|
|
// prevent users from importing files under the game root directory
|
|
if (path.startsWith(gameRootAbsPath, Qt::CaseInsensitive))
|
|
{
|
|
invalidFiles << fileName;
|
|
}
|
|
else
|
|
{
|
|
// store paths into the map.
|
|
m_pathMap[path] = fileName;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
encounteredCrate = true;
|
|
}
|
|
}
|
|
|
|
if (invalidFiles.size() > 0)
|
|
{
|
|
QString fileWarning = QString("Files cannot be imported into their own project. The following files will not be moved or copied:\n");
|
|
fileWarning.append(invalidFiles.join(", "));
|
|
fileWarning.append('.');
|
|
QMessageBox::warning(AzToolsFramework::GetActiveWindow(), AssetImporterManagerPrivate::g_errorMessageBoxTitle, fileWarning);
|
|
}
|
|
if (encounteredCrate)
|
|
{
|
|
QMessageBox::warning(AzToolsFramework::GetActiveWindow(), AssetImporterManagerPrivate::g_errorMessageBoxTitle, AssetImporterManagerPrivate::g_crateError);
|
|
}
|
|
|
|
currentAbsolutePath = fileDialog.directory().absolutePath();
|
|
settings.setValue(AssetImporterManagerPrivate::g_selectFilesPath, currentAbsolutePath);
|
|
|
|
// prevent users from selecting crate files from the File Explorer and open the Asset Importer.
|
|
return (m_pathMap.size() > 0);
|
|
}
|
|
|
|
void AssetImporterManager::OnBrowseDestinationFilePath(QLineEdit* destinationLineEdit)
|
|
{
|
|
QFileDialog fileDialog;
|
|
fileDialog.setOption(QFileDialog::ShowDirsOnly, true);
|
|
fileDialog.setViewMode(QFileDialog::List);
|
|
fileDialog.setWindowModality(Qt::WindowModality::ApplicationModal);
|
|
fileDialog.setWindowTitle(tr("Select import destination"));
|
|
|
|
QSettings settings;
|
|
QString currentDestination = settings.value(AssetImporterManagerPrivate::g_selectDestinationFilesPath).toString();
|
|
|
|
QDir gameRoot(Path::GetEditingGameDataFolder().c_str());
|
|
QString gameRootAbsPath = gameRoot.absolutePath();
|
|
|
|
// Case 1: if currentDestination is empty at this point, that means this is the first time
|
|
// users using the Asset Importer, set the default directory to be the current game project's root folder
|
|
// Case 2: if the current folder directory stored in the registry doesn't exist anymore,
|
|
// that means users have removed the directory already (deleted or use the Move feature).
|
|
// Case 3: if it's a directory outside of the game root folder, then in general,
|
|
// users have modified the folder directory in the registry. It should not be happening.
|
|
if (currentDestination.isEmpty() || !QDir(currentDestination).exists() || !currentDestination.startsWith(gameRootAbsPath, Qt::CaseInsensitive))
|
|
{
|
|
currentDestination = gameRootAbsPath;
|
|
}
|
|
|
|
fileDialog.setDirectory(currentDestination);
|
|
|
|
// The default file path is the game project root folder.
|
|
// After that, the default file path will be the previous opened folder path.
|
|
connect(&fileDialog, &QFileDialog::directoryEntered, this, [&fileDialog, &gameRoot, &gameRootAbsPath](const QString& path)
|
|
{
|
|
// get current relative path
|
|
QString relativePath = gameRoot.relativeFilePath(path);
|
|
|
|
// Guard against navigating outside of the project folder. Lambda used as the dialog had to be captured.
|
|
// checking the directory and prevent users from changing the directory outside of the game root
|
|
if (!path.startsWith(gameRootAbsPath, Qt::CaseInsensitive) || (relativePath.length() > 2 && relativePath[0] == '.' && relativePath[1] == '.'))
|
|
{
|
|
fileDialog.setDirectory(gameRoot);
|
|
}
|
|
});
|
|
|
|
if (!fileDialog.exec())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// users can only select one folder at a time, so the index is always 0.
|
|
// This fixes the issue that QFileDialog does not select the highlighted folder
|
|
QString destinationDirectory = fileDialog.selectedFiles().at(0);
|
|
|
|
OnSetDestinationDirectory(destinationDirectory);
|
|
|
|
destinationLineEdit->setText(destinationDirectory);
|
|
}
|
|
|
|
// Copy + Paste
|
|
void AssetImporterManager::OnCopyFiles()
|
|
{
|
|
m_importMethod = ImportFilesMethod::CopyFiles;
|
|
ProcessCopyFiles();
|
|
}
|
|
|
|
// Cut + Paste
|
|
void AssetImporterManager::OnMoveFiles()
|
|
{
|
|
m_importMethod = ImportFilesMethod::MoveFiles;
|
|
ProcessMoveFiles();
|
|
}
|
|
|
|
bool AssetImporterManager::OnOverwriteFiles(QString relativePath, QString oldAbsolutePath)
|
|
{
|
|
// this is the absolute path in the destination folder
|
|
QString destinationAbsolutePath = GenerateAbsolutePath(relativePath);
|
|
|
|
return Overwrite(relativePath, oldAbsolutePath, destinationAbsolutePath);
|
|
}
|
|
|
|
bool AssetImporterManager::OnKeepBothFiles(QString relativePath, QString oldAbsolutePath)
|
|
{
|
|
// this is the absolute path in the destination folder
|
|
QString destinationAbsolutePath = GenerateAbsolutePath(relativePath);
|
|
|
|
QString subPath = QFileInfo(destinationAbsolutePath).absoluteDir().absolutePath();
|
|
|
|
QFileInfo info(destinationAbsolutePath);
|
|
QString extension = info.completeSuffix(); // extension without '.'
|
|
QString fileName = info.baseName(); //file name without extension
|
|
|
|
int number = 1;
|
|
int index = destinationAbsolutePath.indexOf(extension);
|
|
|
|
QString newFileName = CreateFileNameWithNumber(number, fileName, index, extension);
|
|
QString newDestinationAbsolutePath = subPath + '/' + newFileName;
|
|
|
|
while (QFile(newDestinationAbsolutePath).exists())
|
|
{
|
|
number++;
|
|
newFileName = CreateFileNameWithNumber(number, fileName, index, extension);
|
|
newDestinationAbsolutePath = subPath + '/' + newFileName;
|
|
}
|
|
|
|
if (m_importMethod == ImportFilesMethod::CopyFiles)
|
|
{
|
|
return Copy(relativePath, oldAbsolutePath, newDestinationAbsolutePath);
|
|
}
|
|
else if (m_importMethod == ImportFilesMethod::MoveFiles)
|
|
{
|
|
return Move(relativePath, oldAbsolutePath, newDestinationAbsolutePath);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void AssetImporterManager::OnOpenLogDialog()
|
|
{
|
|
AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::ShowAssetProcessor);
|
|
reject();
|
|
}
|
|
|
|
void AssetImporterManager::OnSetDestinationDirectory(QString destinationDirectory)
|
|
{
|
|
QSettings settings;
|
|
QString currentDestination = settings.value(AssetImporterManagerPrivate::g_selectDestinationFilesPath).toString();
|
|
|
|
m_destinationRootDirectory = (!destinationDirectory.isEmpty()) ? destinationDirectory : currentDestination;
|
|
settings.setValue(AssetImporterManagerPrivate::g_selectDestinationFilesPath, destinationDirectory);
|
|
}
|
|
|
|
void AssetImporterManager::OnOpenSelectDestinationDialog()
|
|
{
|
|
QWidget* mainWindow = nullptr;
|
|
AzToolsFramework::EditorRequestBus::BroadcastResult(mainWindow, &AzToolsFramework::EditorRequests::GetMainWindow);
|
|
|
|
QString numberOfFilesMessage = m_pathMap.size() == 1 ? QString(tr("Importing 1 asset")) : QString(tr("Importing %1 assets").arg(m_pathMap.size()));
|
|
|
|
SelectDestinationDialog selectDestinationDialog(numberOfFilesMessage, mainWindow);
|
|
|
|
// Browse Destination File Path
|
|
connect(&selectDestinationDialog, &SelectDestinationDialog::BrowseDestinationPath, this, &AssetImporterManager::OnBrowseDestinationFilePath);
|
|
connect(&selectDestinationDialog, &SelectDestinationDialog::DoCopyFiles, this, &AssetImporterManager::OnCopyFiles);
|
|
connect(&selectDestinationDialog, &SelectDestinationDialog::DoMoveFiles, this, &AssetImporterManager::OnMoveFiles);
|
|
connect(&selectDestinationDialog, &SelectDestinationDialog::Cancel, this, &AssetImporterManager::reject);
|
|
connect(&selectDestinationDialog, &SelectDestinationDialog::SetDestinationDirectory, this, &AssetImporterManager::OnSetDestinationDirectory);
|
|
selectDestinationDialog.exec();
|
|
}
|
|
|
|
ProcessFilesMethod AssetImporterManager::OnOpenFilesAlreadyExistDialog(QString message, int numberOfFiles)
|
|
{
|
|
ProcessFilesMethod processMethod = ProcessFilesMethod::Default;
|
|
|
|
// make sure the dialog is opened in front of the Editor main window
|
|
QWidget* mainWindow = nullptr;
|
|
AzToolsFramework::EditorRequestBus::BroadcastResult(mainWindow, &AzToolsFramework::EditorRequests::GetMainWindow);
|
|
|
|
FilesAlreadyExistDialog filesAlreadyExistDialog(message, numberOfFiles, mainWindow);
|
|
|
|
bool applyToAll = false;
|
|
|
|
connect(&filesAlreadyExistDialog, &FilesAlreadyExistDialog::ApplyActionToAllFiles, this, [&applyToAll](bool result)
|
|
{
|
|
applyToAll = result;
|
|
});
|
|
|
|
connect(&filesAlreadyExistDialog, &FilesAlreadyExistDialog::OverWriteFiles, this, [this, &processMethod, &applyToAll]()
|
|
{
|
|
processMethod = UpdateProcessFileMethod(ProcessFilesMethod::OverwriteFile, applyToAll);
|
|
});
|
|
|
|
connect(&filesAlreadyExistDialog, &FilesAlreadyExistDialog::KeepBothFiles, this, [this, &processMethod, &applyToAll]()
|
|
{
|
|
processMethod = UpdateProcessFileMethod(ProcessFilesMethod::KeepBothFile, applyToAll);
|
|
});
|
|
|
|
connect(&filesAlreadyExistDialog, &FilesAlreadyExistDialog::SkipCurrentProcess, this, [this, &processMethod, &applyToAll]()
|
|
{
|
|
processMethod = UpdateProcessFileMethod(ProcessFilesMethod::SkipProcessingFile, applyToAll);
|
|
});
|
|
|
|
connect(&filesAlreadyExistDialog, &FilesAlreadyExistDialog::CancelAllProcesses, this, [&processMethod]()
|
|
{
|
|
processMethod = ProcessFilesMethod::Cancel;
|
|
});
|
|
|
|
if (!applyToAll && processMethod != ProcessFilesMethod::Cancel)
|
|
{
|
|
filesAlreadyExistDialog.exec();
|
|
}
|
|
|
|
return processMethod;
|
|
}
|
|
|
|
ProcessFilesMethod AssetImporterManager::UpdateProcessFileMethod(ProcessFilesMethod processMethod, bool applyToAll)
|
|
{
|
|
if (applyToAll)
|
|
{
|
|
switch (processMethod)
|
|
{
|
|
case ProcessFilesMethod::OverwriteFile:
|
|
processMethod = ProcessFilesMethod::OverwriteAllFiles;
|
|
break;
|
|
case ProcessFilesMethod::KeepBothFile:
|
|
processMethod = ProcessFilesMethod::KeepBothAllFiles;
|
|
break;
|
|
case ProcessFilesMethod::SkipProcessingFile:
|
|
processMethod = ProcessFilesMethod::SkipProcessingAllFiles;
|
|
}
|
|
}
|
|
|
|
return processMethod;
|
|
}
|
|
|
|
bool AssetImporterManager::ProcessFileMethod(ProcessFilesMethod processMethod, QString relativePath, QString oldAbsolutePath)
|
|
{
|
|
switch (processMethod)
|
|
{
|
|
case ProcessFilesMethod::OverwriteFile:
|
|
case ProcessFilesMethod::OverwriteAllFiles:
|
|
return OnOverwriteFiles(relativePath, oldAbsolutePath);
|
|
case ProcessFilesMethod::KeepBothFile:
|
|
case ProcessFilesMethod::KeepBothAllFiles:
|
|
return OnKeepBothFiles(relativePath, oldAbsolutePath);
|
|
case ProcessFilesMethod::SkipProcessingAllFiles:
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void AssetImporterManager::OnOpenProcessingAssetsDialog(int numberOfProcessedFiles)
|
|
{
|
|
// make sure the dialog is opened in front of the Editor main window
|
|
QWidget* mainWindow = nullptr;
|
|
AzToolsFramework::EditorRequestBus::BroadcastResult(mainWindow, &AzToolsFramework::EditorRequests::GetMainWindow);
|
|
|
|
ProcessingAssetsDialog processingAssetsDialog(numberOfProcessedFiles, mainWindow);
|
|
connect(&processingAssetsDialog, &ProcessingAssetsDialog::OpenLogDialog, this, &AssetImporterManager::OnOpenLogDialog);
|
|
connect(&processingAssetsDialog, &ProcessingAssetsDialog::CloseProcessingAssetsDialog, this, &AssetImporterManager::reject);
|
|
|
|
processingAssetsDialog.exec();
|
|
}
|
|
|
|
void AssetImporterManager::ProcessCopyFiles()
|
|
{
|
|
int numberOfFiles = m_pathMap.size();
|
|
int numberOfProcessedFiles = 0;
|
|
|
|
ProcessFilesMethod processMethod = ProcessFilesMethod::Default;
|
|
|
|
for (int i = 0; i < m_pathMap.size(); ++i)
|
|
{
|
|
QString relativePath = m_pathMap.values().at(i);
|
|
QString oldAbsolutePath = m_pathMap.keys().at(i);
|
|
|
|
// this is the absolute path in the destination folder
|
|
QString destinationAbsolutePath = GenerateAbsolutePath(relativePath);
|
|
|
|
// check if the file exists in the destination folder
|
|
if (!QFile::exists(destinationAbsolutePath))
|
|
{
|
|
if (Copy(relativePath, oldAbsolutePath, destinationAbsolutePath))
|
|
{
|
|
numberOfProcessedFiles++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (processMethod == ProcessFilesMethod::Default ||
|
|
processMethod == ProcessFilesMethod::OverwriteFile ||
|
|
processMethod == ProcessFilesMethod::KeepBothFile ||
|
|
processMethod == ProcessFilesMethod::SkipProcessingFile)
|
|
{
|
|
QString fileName = GetFileName(oldAbsolutePath);
|
|
QString message = QString("The destination already has a file named \"%1\". What would you like to do?").arg(fileName);
|
|
|
|
processMethod = OnOpenFilesAlreadyExistDialog(message, numberOfFiles);
|
|
}
|
|
|
|
if (ProcessFileMethod(processMethod, relativePath, oldAbsolutePath))
|
|
{
|
|
numberOfProcessedFiles++;
|
|
}
|
|
}
|
|
|
|
numberOfFiles--;
|
|
}
|
|
|
|
if (numberOfProcessedFiles > 0)
|
|
{
|
|
OnOpenProcessingAssetsDialog(numberOfProcessedFiles);
|
|
}
|
|
else
|
|
{
|
|
reject();
|
|
}
|
|
}
|
|
|
|
void AssetImporterManager::ProcessMoveFiles()
|
|
{
|
|
int numberOfFiles = m_pathMap.size();
|
|
int numberOfProcessedFiles = 0;
|
|
|
|
ProcessFilesMethod processMethod = ProcessFilesMethod::Default;
|
|
|
|
for (int i = 0; i < m_pathMap.size(); ++i)
|
|
{
|
|
QString relativePath = m_pathMap.values().at(i);
|
|
QString oldAbsolutePath = m_pathMap.keys().at(i);
|
|
|
|
// this is the absolute path in the destination folder
|
|
QString destinationAbsolutePath = GenerateAbsolutePath(relativePath);
|
|
|
|
// check if the file exists in the destination folder
|
|
if (!QFile::exists(destinationAbsolutePath))
|
|
{
|
|
if (Move(relativePath, oldAbsolutePath, destinationAbsolutePath))
|
|
{
|
|
numberOfProcessedFiles++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (processMethod == ProcessFilesMethod::Default ||
|
|
processMethod == ProcessFilesMethod::OverwriteFile ||
|
|
processMethod == ProcessFilesMethod::KeepBothFile ||
|
|
processMethod == ProcessFilesMethod::SkipProcessingFile)
|
|
{
|
|
QString fileName = GetFileName(oldAbsolutePath);
|
|
QString message = QString("The destination already has a file named \"%1\". What would you like to do?").arg(fileName);
|
|
|
|
processMethod = OnOpenFilesAlreadyExistDialog(message, numberOfFiles);
|
|
}
|
|
|
|
if (ProcessFileMethod(processMethod, relativePath, oldAbsolutePath))
|
|
{
|
|
numberOfProcessedFiles++;
|
|
}
|
|
}
|
|
|
|
numberOfFiles--;
|
|
}
|
|
|
|
if (numberOfProcessedFiles > 0)
|
|
{
|
|
OnOpenProcessingAssetsDialog(numberOfProcessedFiles);
|
|
}
|
|
else
|
|
{
|
|
reject();
|
|
}
|
|
}
|
|
|
|
bool AssetImporterManager::Copy(QString relativePath, QString oldAbsolutePath, QString destinationAbsolutePath)
|
|
{
|
|
QString fileName = GetFileName(destinationAbsolutePath);
|
|
QString subPath = QFileInfo(destinationAbsolutePath).absoluteDir().absolutePath();
|
|
QDir dir;
|
|
|
|
bool directoryExistedAlready = QDir(subPath).exists();
|
|
if (!directoryExistedAlready)
|
|
{
|
|
dir.mkpath(subPath);
|
|
}
|
|
|
|
QString newDestinationAbsolutePath = subPath;
|
|
newDestinationAbsolutePath = newDestinationAbsolutePath.append('/' + fileName);
|
|
|
|
// Copy the file from the old path to the new path
|
|
if (!QFile::copy(oldAbsolutePath, newDestinationAbsolutePath))
|
|
{
|
|
QString reason = tr("an unknown issue occurred.");
|
|
|
|
if (!directoryExistedAlready)
|
|
{
|
|
dir.rmdir(subPath);
|
|
}
|
|
|
|
// if the original files got deleted at this condition
|
|
if (!QFile(oldAbsolutePath).exists())
|
|
{
|
|
reason = tr("%1 no longer exists.").arg(fileName);
|
|
}
|
|
// if users manually copy the file into the destination folder at this condition
|
|
if (QFile(newDestinationAbsolutePath).exists())
|
|
{
|
|
reason = tr("%1 already exists in the target directory.").arg(fileName);
|
|
}
|
|
|
|
QMessageBox::critical(AzToolsFramework::GetActiveWindow(), AssetImporterManagerPrivate::g_errorMessageBoxTitle, QObject::tr("We're sorry, but the file failed to process because %1").arg(reason));
|
|
return false;
|
|
}
|
|
|
|
// set the destination file to be writable by user himself/herself if it's read-only
|
|
QFile destinationFile(newDestinationAbsolutePath);
|
|
SetDestinationFileWritable(destinationFile);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool AssetImporterManager::Move(QString relativePath, QString oldAbsolutePath, QString destinationAbsolutePath)
|
|
{
|
|
QString fileName = GetFileName(destinationAbsolutePath);
|
|
QString subPath = QFileInfo(destinationAbsolutePath).absoluteDir().absolutePath();
|
|
QString newDestinationAbsolutePath = subPath;
|
|
QDir dir;
|
|
|
|
bool directoryExistedAlready = QDir(subPath).exists();
|
|
if (!directoryExistedAlready)
|
|
{
|
|
dir.mkpath(subPath);
|
|
}
|
|
|
|
if (QFile::rename(oldAbsolutePath, newDestinationAbsolutePath.append('/' + fileName)))
|
|
{
|
|
QString oldFileName = GetFileName(oldAbsolutePath);
|
|
|
|
// Only remove the old directory if the relative path is the file name itself.
|
|
// That also means users are dragging and dropping files, but not a folder containing those files.
|
|
if (oldFileName.compare(relativePath) != 0)
|
|
{
|
|
RemoveOldPath(oldAbsolutePath, relativePath);
|
|
}
|
|
|
|
// set the destination file to be writable by user himself/herself if it's read-only
|
|
QFile destinationFile(newDestinationAbsolutePath);
|
|
SetDestinationFileWritable(destinationFile);
|
|
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
QString reason = tr("an unknown issue occurred.");
|
|
QString oldFileName = GetFileName(oldAbsolutePath);
|
|
|
|
if (!directoryExistedAlready)
|
|
{
|
|
dir.rmdir(subPath);
|
|
}
|
|
|
|
// if the original files got deleted at this condition
|
|
if (!QFile(oldAbsolutePath).exists())
|
|
{
|
|
reason = tr("%1 no longer exists.").arg(oldFileName);
|
|
}
|
|
// if users manually copy the file into the destination folder at this condition
|
|
if (QFile(newDestinationAbsolutePath).exists())
|
|
{
|
|
reason = tr("%1 already exists in the target directory.").arg(oldFileName);
|
|
}
|
|
|
|
QMessageBox::critical(AzToolsFramework::GetActiveWindow(), AssetImporterManagerPrivate::g_errorMessageBoxTitle, QObject::tr("We're sorry, but the file failed to process because %1").arg(reason));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool AssetImporterManager::Overwrite(QString relativePath, QString oldAbsolutePath, QString destinationAbsolutePath)
|
|
{
|
|
QFile newFile(destinationAbsolutePath);
|
|
QFile oldFile(oldAbsolutePath);
|
|
|
|
// double check if paths are valid
|
|
if ((!oldFile.open(QIODevice::ReadOnly)))
|
|
{
|
|
QString fileName = GetFileName(oldAbsolutePath);
|
|
QString reason = tr("%1 no longer exists.").arg(fileName);
|
|
QMessageBox::critical(AzToolsFramework::GetActiveWindow(), AssetImporterManagerPrivate::g_errorMessageBoxTitle, QObject::tr("We're sorry, but the file failed to process because %1").arg(reason));
|
|
return false;
|
|
}
|
|
|
|
if (!newFile.open(QIODevice::WriteOnly | QIODevice::Truncate))
|
|
{
|
|
QString reason = tr("We're sorry, but the file failed to process.");
|
|
QString fileName = GetFileName(destinationAbsolutePath);
|
|
|
|
if (!newFile.exists())
|
|
{
|
|
reason = tr("%1 from the destination directory is removed.").arg(fileName);
|
|
}
|
|
else
|
|
{
|
|
reason = tr("%1 from the destination directory cannot be overwritten.").arg(fileName);
|
|
}
|
|
|
|
QMessageBox::critical(AzToolsFramework::GetActiveWindow(), AssetImporterManagerPrivate::g_errorMessageBoxTitle, QObject::tr("We're sorry, but the file failed to process because %1").arg(reason));
|
|
return false;
|
|
}
|
|
|
|
QDataStream dataStream(&oldFile);
|
|
QDataStream out(&newFile);
|
|
|
|
int bufferSize = 1024 * 1024;
|
|
char* buffer = new char[bufferSize];
|
|
|
|
while (!dataStream.atEnd())
|
|
{
|
|
int bytesRead = dataStream.readRawData(buffer, bufferSize);
|
|
out.writeRawData(buffer, bytesRead);
|
|
}
|
|
|
|
delete[] buffer;
|
|
oldFile.close();
|
|
newFile.close();
|
|
|
|
// if it's the move file method, got to remove the original files
|
|
if (m_importMethod == ImportFilesMethod::MoveFiles)
|
|
{
|
|
QString fileName = GetFileName(oldAbsolutePath);
|
|
QFile file(oldAbsolutePath);
|
|
QDir absoluteDir = QFileInfo(oldAbsolutePath).absoluteDir();
|
|
|
|
if (file.exists())
|
|
{
|
|
// if the original file is read-only,
|
|
// then it got to be writable in order to be deleted successfully
|
|
SetDestinationFileWritable(file);
|
|
absoluteDir.remove(fileName);
|
|
}
|
|
|
|
// Only remove the old directory if the relative path is the file name itself.
|
|
// That also means users are dragging and dropping files, but not a folder containing those files.
|
|
if (fileName.compare(relativePath) != 0)
|
|
{
|
|
RemoveOldPath(oldAbsolutePath, relativePath);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool AssetImporterManager::GetAndCheckAllFilesInFolder(QString path)
|
|
{
|
|
QString formattedPath = path;
|
|
|
|
// Paths ending with '/' return from QFileInfo().fileName() with a value of ""
|
|
// Strip a trailing slash so we can correctly get rootFolderName on all platforms
|
|
if (formattedPath.endsWith("/"))
|
|
{
|
|
formattedPath.truncate(formattedPath.lastIndexOf(QChar('/')));
|
|
}
|
|
|
|
QString rootFolderName = GetFileName(formattedPath);
|
|
QDirIterator it(formattedPath, QDir::NoDotAndDotDot | QDir::Files, QDirIterator::Subdirectories);
|
|
QFileInfo info(formattedPath);
|
|
|
|
if (!info.isDir() && !it.hasNext() && info.exists())
|
|
{
|
|
m_pathMap[formattedPath] = rootFolderName;
|
|
return true;
|
|
}
|
|
|
|
// Get the index of the last sub folder name in the path
|
|
QStringList directoryNameList = formattedPath.split('/');
|
|
int lastFolderIndex = directoryNameList.size() - 1;
|
|
|
|
QString pathToBeRelativeTo = directoryNameList.mid(0, lastFolderIndex).join('/');
|
|
|
|
while (it.hasNext())
|
|
{
|
|
QString absolutePath = it.next();
|
|
QFileInfo absoluteInfo(absolutePath);
|
|
QString extension = absoluteInfo.completeSuffix();
|
|
|
|
if (QString(AssetImporterManagerPrivate::s_crateFileExtension).compare(extension, Qt::CaseInsensitive) == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Q_ASSERT(absolutePath.startsWith(pathToBeRelativeTo));
|
|
QString relativePath = absolutePath.mid(pathToBeRelativeTo.size() + 1);
|
|
m_pathMap[absolutePath] = relativePath;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void AssetImporterManager::RemoveOldPath(QString oldAbsolutePath, QString oldRelativePath)
|
|
{
|
|
QDir absoluteDir = QFileInfo(oldAbsolutePath).absoluteDir();
|
|
QStringList directoryList = oldRelativePath.split('/');
|
|
|
|
// remove each folder from the leave to the root, based on the relative path
|
|
for (int i = 0; i < directoryList.size(); ++i)
|
|
{
|
|
QString currentDir = absoluteDir.path();
|
|
absoluteDir.rmpath(currentDir);
|
|
absoluteDir.cdUp();
|
|
}
|
|
}
|
|
|
|
void AssetImporterManager::SetDestinationFileWritable(QFile& destinationFile)
|
|
{
|
|
if (destinationFile.open(QIODevice::ReadOnly))
|
|
{
|
|
destinationFile.setPermissions(QFile::WriteOwner | destinationFile.permissions());
|
|
}
|
|
|
|
destinationFile.close();
|
|
}
|
|
|
|
QString AssetImporterManager::CreateFileNameWithNumber(int number, QString fileName, int index, QString extension)
|
|
{
|
|
QString newFileName;
|
|
|
|
newFileName = fileName.isEmpty() ? fileName : fileName.left(index);
|
|
|
|
newFileName += "(" + QString::number(number) + ")";
|
|
|
|
if (extension.size() > 0)
|
|
{
|
|
newFileName += "." + extension;
|
|
}
|
|
|
|
return newFileName;
|
|
}
|
|
|
|
QString AssetImporterManager::GenerateAbsolutePath(QString relativePath)
|
|
{
|
|
return QDir(m_destinationRootDirectory).absoluteFilePath(relativePath);
|
|
}
|
|
|
|
QString AssetImporterManager::GetFileName(QString path)
|
|
{
|
|
return QFileInfo(path).fileName();
|
|
}
|
|
|
|
#include <AssetImporter/AssetImporterManager/moc_AssetImporterManager.cpp>
|