@ -6,6 +6,7 @@
*/
# include <ProjectUtils.h>
# include <ProjectManagerDefs.h>
# include <PythonBindingsInterface.h>
# include <QFileDialog>
@ -59,29 +60,63 @@ namespace O3DE::ProjectManager
return false ;
}
static bool SkipFilePaths ( const QString & curPath , QStringList & skippedPaths , QStringList & deeperSkippedPaths )
{
bool skip = false ;
for ( const QString & skippedPath : skippedPaths )
{
QString nativeSkippedPath = QDir : : toNativeSeparators ( skippedPath ) ;
QString firstSectionSkippedPath = nativeSkippedPath . section ( QDir : : separator ( ) , 0 , 0 ) ;
if ( curPath = = firstSectionSkippedPath )
{
// We are at the end of the path to skip, so skip it
if ( nativeSkippedPath = = firstSectionSkippedPath )
{
skippedPaths . removeAll ( skippedPath ) ;
skip = true ;
break ;
}
// Append the next section of the skipped path
else
{
deeperSkippedPaths . append ( nativeSkippedPath . section ( QDir : : separator ( ) , 1 ) ) ;
}
}
}
return skip ;
}
typedef AZStd : : function < void ( /*fileCount=*/ int , /*totalSizeInBytes=*/ int ) > StatusFunction ;
static void RecursiveGetAllFiles ( const QDir & directory , QStringList & outFileList , qint64 & outTotalSizeInBytes , StatusFunction statusCallback )
static void RecursiveGetAllFiles ( const QDir & directory , QStringList & skippedPaths, int & outFileCoun t, qint64 & outTotalSizeInBytes , StatusFunction statusCallback )
{
const QStringList entries = directory . entryList ( QDir : : Dirs | QDir : : Files | QDir : : NoSymLinks | QDir : : NoDotAndDotDot ) ;
for ( const QString & entryPath : entries )
{
const QString filePath = QDir : : toNativeSeparators ( QString ( " %1/%2 " ) . arg ( directory . path ( ) ) . arg ( entryPath ) ) ;
QStringList deeperSkippedPaths ;
if ( SkipFilePaths ( entryPath , skippedPaths , deeperSkippedPaths ) )
{
continue ;
}
QFileInfo fileInfo ( filePath ) ;
if ( fileInfo . isDir ( ) )
{
QDir subDirectory ( filePath ) ;
RecursiveGetAllFiles ( subDirectory , outFileList , outTotalSizeInBytes , statusCallback ) ;
RecursiveGetAllFiles ( subDirectory , deeperSkippedPaths, outFileCoun t, outTotalSizeInBytes , statusCallback ) ;
}
else
{
outFileList . push_back ( filePath ) ;
+ + outFileCount ;
outTotalSizeInBytes + = fileInfo . size ( ) ;
const int updateStatusEvery = 64 ;
if ( outFileList . size ( ) % updateStatusEvery = = 0 )
if ( outFile Count % updateStatusEvery = = 0 )
{
statusCallback ( outFileList . size ( ) , outTotalSizeInBytes ) ;
statusCallback ( outFile Count , outTotalSizeInBytes ) ;
}
}
}
@ -90,7 +125,8 @@ namespace O3DE::ProjectManager
static bool CopyDirectory ( QProgressDialog * progressDialog ,
const QString & origPath ,
const QString & newPath ,
QStringList & filesToCopy ,
QStringList & skippedPaths ,
int filesToCopyCount ,
int & outNumCopiedFiles ,
qint64 totalSizeToCopy ,
qint64 & outCopiedFileSize ,
@ -102,18 +138,24 @@ namespace O3DE::ProjectManager
return false ;
}
for ( QString directory : original . entryList ( QDir : : Dirs | QDir : : NoDotAndDotDot ) )
for ( const QString & directory : original . entryList ( QDir : : Dirs | QDir : : NoDotAndDotDot ) )
{
if ( progressDialog - > wasCanceled ( ) )
{
return false ;
}
QStringList deeperSkippedPaths ;
if ( SkipFilePaths ( directory , skippedPaths , deeperSkippedPaths ) )
{
continue ;
}
QString newDirectoryPath = newPath + QDir : : separator ( ) + directory ;
original . mkpath ( newDirectoryPath ) ;
if ( ! CopyDirectory ( progressDialog , origPath + QDir : : separator ( ) + directory ,
newDirectoryPath , filesToCopy , outNumCopiedFiles , totalSizeToCopy , outCopiedFileSize , showIgnoreFileDialog ) )
if ( ! CopyDirectory ( progressDialog , origPath + QDir : : separator ( ) + directory , newDirectoryPath , deeperSkippedPaths ,
filesToCopyCount , outNumCopiedFiles , totalSizeToCopy , outCopiedFileSize , showIgnoreFileDialog ) )
{
return false ;
}
@ -121,18 +163,25 @@ namespace O3DE::ProjectManager
QLocale locale ;
const float progressDialogRangeHalf = qFabs ( progressDialog - > maximum ( ) - progressDialog - > minimum ( ) ) * 0.5f ;
for ( QString file : original . entryList ( QDir : : Files ) )
for ( const QString & file : original . entryList ( QDir : : Files ) )
{
if ( progressDialog - > wasCanceled ( ) )
{
return false ;
}
// Unused by this function but neccesary to pass in to SkipFilePaths
QStringList deeperSkippedPaths ;
if ( SkipFilePaths ( file , skippedPaths , deeperSkippedPaths ) )
{
continue ;
}
// Progress window update
{
// Weight in the number of already copied files as well as the copied bytes to get a better progress indication
// for cases combining many small files and some really large files.
const float normalizedNumFiles = static_cast < float > ( outNumCopiedFiles ) / filesToCopy . count ( ) ;
const float normalizedNumFiles = static_cast < float > ( outNumCopiedFiles ) / filesToCopy Count ;
const float normalizedFileSize = static_cast < float > ( outCopiedFileSize ) / totalSizeToCopy ;
const int progress = normalizedNumFiles * progressDialogRangeHalf + normalizedFileSize * progressDialogRangeHalf ;
progressDialog - > setValue ( progress ) ;
@ -140,7 +189,7 @@ namespace O3DE::ProjectManager
const QString copiedFileSizeString = locale . formattedDataSize ( outCopiedFileSize ) ;
const QString totalFileSizeString = locale . formattedDataSize ( totalSizeToCopy ) ;
progressDialog - > setLabelText ( QString ( " Coping file %1 of %2 (%3 of %4) ... " ) . arg ( QString : : number ( outNumCopiedFiles ) ,
QString : : number ( filesToCopy . count ( ) ) ,
QString : : number ( filesToCopy Count ) ,
copiedFileSizeString ,
totalFileSizeString ) ) ;
qApp - > processEvents ( QEventLoop : : ExcludeUserInputEvents ) ;
@ -194,6 +243,39 @@ namespace O3DE::ProjectManager
return true ;
}
static bool ClearProjectBuildArtifactsAndCache ( const QString & origPath , const QString & newPath , QWidget * parent )
{
QDir buildDirectory = QDir ( newPath ) ;
if ( ( ! buildDirectory . cd ( ProjectBuildDirectoryName ) | | ! DeleteProjectFiles ( buildDirectory . path ( ) , true ) )
& & QDir ( origPath ) . cd ( ProjectBuildDirectoryName ) )
{
QMessageBox : : warning (
parent ,
QObject : : tr ( " Clear Build Artifacts " ) ,
QObject : : tr ( " Build artifacts failed to delete for moved project. Please manually delete build directory at \" %1 \" " )
. arg ( buildDirectory . path ( ) ) ,
QMessageBox : : Close ) ;
return false ;
}
QDir cacheDirectory = QDir ( newPath ) ;
if ( ( ! cacheDirectory . cd ( ProjectCacheDirectoryName ) | | ! DeleteProjectFiles ( cacheDirectory . path ( ) , true ) )
& & QDir ( origPath ) . cd ( ProjectCacheDirectoryName ) )
{
QMessageBox : : warning (
parent ,
QObject : : tr ( " Clear Asset Cache " ) ,
QObject : : tr ( " Asset cache failed to delete for moved project. Please manually delete cache directory at \" %1 \" " )
. arg ( cacheDirectory . path ( ) ) ,
QMessageBox : : Close ) ;
return false ;
}
return false ;
}
bool AddProjectDialog ( QWidget * parent )
{
QString path = QDir : : toNativeSeparators ( QFileDialog : : getExistingDirectory ( parent , QObject : : tr ( " Select Project Directory " ) ) ) ;
@ -215,7 +297,7 @@ namespace O3DE::ProjectManager
return PythonBindingsInterface : : Get ( ) - > RemoveProject ( path ) ;
}
bool CopyProjectDialog ( const QString & origPath , QWidget* parent )
bool CopyProjectDialog ( const QString & origPath , ProjectInfo& newProjectInfo , QWidget* parent )
{
bool copyResult = false ;
@ -225,6 +307,8 @@ namespace O3DE::ProjectManager
QFileDialog : : getExistingDirectory ( parent , QObject : : tr ( " Select New Project Directory " ) , parentOrigDir . path ( ) ) ) ;
if ( ! newPath . isEmpty ( ) )
{
newProjectInfo . m_path = newPath ;
if ( ! WarnDirectoryOverwrite ( newPath , parent ) )
{
return false ;
@ -236,7 +320,7 @@ namespace O3DE::ProjectManager
return copyResult ;
}
bool CopyProject ( const QString & origPath , const QString & newPath , QWidget * parent )
bool CopyProject ( const QString & origPath , const QString & newPath , QWidget * parent , bool skipRegister )
{
// Disallow copying from or into subdirectory
if ( IsDirectoryDescedent ( origPath , newPath ) | | IsDirectoryDescedent ( newPath , origPath ) )
@ -244,8 +328,13 @@ namespace O3DE::ProjectManager
return false ;
}
QStringList filesToCopy ;
int filesToCopyCount = 0 ;
qint64 totalSizeInBytes = 0 ;
QStringList skippedPaths
{
ProjectBuildDirectoryName ,
ProjectCacheDirectoryName
} ;
QProgressDialog * progressDialog = new QProgressDialog ( parent ) ;
progressDialog - > setAutoClose ( true ) ;
@ -256,7 +345,8 @@ namespace O3DE::ProjectManager
progressDialog - > show ( ) ;
QLocale locale ;
RecursiveGetAllFiles ( origPath , filesToCopy , totalSizeInBytes , [ = ] ( int fileCount , int sizeInBytes )
QStringList getFilesSkippedPaths ( skippedPaths ) ;
RecursiveGetAllFiles ( origPath , getFilesSkippedPaths , filesToCopyCount , totalSizeInBytes , [ = ] ( int fileCount , int sizeInBytes )
{
// Create a human-readable version of the file size.
const QString fileSizeString = locale . formattedDataSize ( sizeInBytes ) ;
@ -275,8 +365,10 @@ namespace O3DE::ProjectManager
// Phase 1: Copy files
bool showIgnoreFileDialog = true ;
bool success = CopyDirectory ( progressDialog , origPath , newPath , filesToCopy , numFilesCopied , totalSizeInBytes , copiedFileSize , showIgnoreFileDialog ) ;
if ( success )
QStringList copyFilesSkippedPaths ( skippedPaths ) ;
bool success = CopyDirectory ( progressDialog , origPath , newPath , copyFilesSkippedPaths , filesToCopyCount , numFilesCopied ,
totalSizeInBytes , copiedFileSize , showIgnoreFileDialog ) ;
if ( success & & ! skipRegister )
{
// Phase 2: Register project
success = RegisterProject ( newPath ) ;
@ -299,7 +391,7 @@ namespace O3DE::ProjectManager
QDir projectDirectory ( path ) ;
if ( projectDirectory . exists ( ) )
{
// Check if there is an actual project here or just force it
// Check if there is an actual project here or just force it
if ( force | | PythonBindingsInterface : : Get ( ) - > GetProject ( path ) . IsSuccess ( ) )
{
return projectDirectory . removeRecursively ( ) ;
@ -309,12 +401,12 @@ namespace O3DE::ProjectManager
return false ;
}
bool MoveProject ( QString origPath , QString newPath , QWidget * parent , bool ignore Register)
bool MoveProject ( QString origPath , QString newPath , QWidget * parent , bool skip Register)
{
origPath = QDir : : toNativeSeparators ( origPath ) ;
newPath = QDir : : toNativeSeparators ( newPath ) ;
if ( ! WarnDirectoryOverwrite ( newPath , parent ) | | ( ! ignore Register & & ! UnregisterProject ( origPath ) ) )
if ( ! WarnDirectoryOverwrite ( newPath , parent ) | | ( ! skip Register & & ! UnregisterProject ( origPath ) ) )
{
return false ;
}
@ -334,8 +426,13 @@ namespace O3DE::ProjectManager
DeleteProjectFiles ( origPath , true ) ;
}
else
{
// If directoy rename succeeded then build and cache directories need to be deleted seperately
ClearProjectBuildArtifactsAndCache ( origPath , newPath , parent ) ;
}
if ( ! ignoreRegister & & ! RegisterProject ( newPath ) )
if ( ! skip Register & & ! RegisterProject ( newPath ) )
{
return false ;
}