diff --git a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp index cf597745ea..4efa9d1d0f 100644 --- a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp +++ b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include @@ -46,28 +46,28 @@ namespace O3DE::ProjectManager m_engineVersion->lineEdit()->setReadOnly(true); layout->addWidget(m_engineVersion); - m_thirdParty = new FormBrowseEditWidget(tr("3rd Party Software Folder"), engineInfo.m_thirdPartyPath, this); + m_thirdParty = new FormFolderBrowseEditWidget(tr("3rd Party Software Folder"), engineInfo.m_thirdPartyPath, this); m_thirdParty->lineEdit()->setValidator(new PathValidator(PathValidator::PathMode::ExistingFolder, this)); m_thirdParty->lineEdit()->setReadOnly(true); m_thirdParty->setErrorLabelText(tr("Please provide a valid path to a folder that exists")); connect(m_thirdParty->lineEdit(), &QLineEdit::textChanged, this, &EngineSettingsScreen::OnTextChanged); layout->addWidget(m_thirdParty); - m_defaultProjects = new FormBrowseEditWidget(tr("Default Projects Folder"), engineInfo.m_defaultProjectsFolder, this); + m_defaultProjects = new FormFolderBrowseEditWidget(tr("Default Projects Folder"), engineInfo.m_defaultProjectsFolder, this); m_defaultProjects->lineEdit()->setValidator(new PathValidator(PathValidator::PathMode::ExistingFolder, this)); m_defaultProjects->lineEdit()->setReadOnly(true); m_defaultProjects->setErrorLabelText(tr("Please provide a valid path to a folder that exists")); connect(m_defaultProjects->lineEdit(), &QLineEdit::textChanged, this, &EngineSettingsScreen::OnTextChanged); layout->addWidget(m_defaultProjects); - m_defaultGems = new FormBrowseEditWidget(tr("Default Gems Folder"), engineInfo.m_defaultGemsFolder, this); + m_defaultGems = new FormFolderBrowseEditWidget(tr("Default Gems Folder"), engineInfo.m_defaultGemsFolder, this); m_defaultGems->lineEdit()->setValidator(new PathValidator(PathValidator::PathMode::ExistingFolder, this)); m_defaultGems->lineEdit()->setReadOnly(true); m_defaultGems->setErrorLabelText(tr("Please provide a valid path to a folder that exists")); connect(m_defaultGems->lineEdit(), &QLineEdit::textChanged, this, &EngineSettingsScreen::OnTextChanged); layout->addWidget(m_defaultGems); - m_defaultProjectTemplates = new FormBrowseEditWidget(tr("Default Project Templates Folder"), engineInfo.m_defaultTemplatesFolder, this); + m_defaultProjectTemplates = new FormFolderBrowseEditWidget(tr("Default Project Templates Folder"), engineInfo.m_defaultTemplatesFolder, this); m_defaultProjectTemplates->lineEdit()->setValidator(new PathValidator(PathValidator::PathMode::ExistingFolder, this)); m_defaultProjectTemplates->lineEdit()->setReadOnly(true); m_defaultProjectTemplates->setErrorLabelText(tr("Please provide a valid path to a folder that exists")); diff --git a/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.cpp b/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.cpp index c30d6a7b30..9a2227cf4a 100644 --- a/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.cpp +++ b/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.cpp @@ -11,13 +11,9 @@ */ #include -#include + #include #include -#include -#include -#include -#include namespace O3DE::ProjectManager { @@ -30,20 +26,4 @@ namespace O3DE::ProjectManager connect(browseButton, &QPushButton::pressed, this, &FormBrowseEditWidget::HandleBrowseButton); m_frameLayout->addWidget(browseButton); } - - void FormBrowseEditWidget::HandleBrowseButton() - { - QString defaultPath = m_lineEdit->text(); - if (defaultPath.isEmpty()) - { - defaultPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); - } - - QString directory = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this, tr("Browse"), defaultPath)); - if (!directory.isEmpty()) - { - m_lineEdit->setText(directory); - } - - } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.h b/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.h index 887fc29dd9..1eba97654b 100644 --- a/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.h +++ b/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.h @@ -27,7 +27,7 @@ namespace O3DE::ProjectManager explicit FormBrowseEditWidget(const QString& labelText, const QString& valueText = "", QWidget* parent = nullptr); ~FormBrowseEditWidget() = default; - private slots: - void HandleBrowseButton(); + protected slots: + virtual void HandleBrowseButton() = 0; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/FormFolderBrowseEditWidget.cpp b/Code/Tools/ProjectManager/Source/FormFolderBrowseEditWidget.cpp new file mode 100644 index 0000000000..2c4cad5adb --- /dev/null +++ b/Code/Tools/ProjectManager/Source/FormFolderBrowseEditWidget.cpp @@ -0,0 +1,42 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include +#include + +#include +#include +#include + +namespace O3DE::ProjectManager +{ + FormFolderBrowseEditWidget::FormFolderBrowseEditWidget(const QString& labelText, const QString& valueText, QWidget* parent) + : FormBrowseEditWidget(labelText, valueText, parent) + { + } + + void FormFolderBrowseEditWidget::HandleBrowseButton() + { + QString defaultPath = m_lineEdit->text(); + if (defaultPath.isEmpty()) + { + defaultPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); + } + + QString directory = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this, tr("Browse"), defaultPath)); + if (!directory.isEmpty()) + { + m_lineEdit->setText(directory); + } + + } +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/FormFolderBrowseEditWidget.h b/Code/Tools/ProjectManager/Source/FormFolderBrowseEditWidget.h new file mode 100644 index 0000000000..a99fe3b5c2 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/FormFolderBrowseEditWidget.h @@ -0,0 +1,33 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#if !defined(Q_MOC_RUN) +#include +#endif + +namespace O3DE::ProjectManager +{ + class FormFolderBrowseEditWidget + : public FormBrowseEditWidget + { + Q_OBJECT + + public: + explicit FormFolderBrowseEditWidget(const QString& labelText, const QString& valueText = "", QWidget* parent = nullptr); + ~FormFolderBrowseEditWidget() = default; + + protected: + void HandleBrowseButton() override; + }; +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/FormImageBrowseEditWidget.cpp b/Code/Tools/ProjectManager/Source/FormImageBrowseEditWidget.cpp new file mode 100644 index 0000000000..5bb9d61dd6 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/FormImageBrowseEditWidget.cpp @@ -0,0 +1,35 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include +#include + +#include +#include + +namespace O3DE::ProjectManager +{ + FormImageBrowseEditWidget::FormImageBrowseEditWidget(const QString& labelText, const QString& valueText, QWidget* parent) + : FormBrowseEditWidget(labelText, valueText, parent) + { + } + + void FormImageBrowseEditWidget::HandleBrowseButton() + { + QString file = QDir::toNativeSeparators(QFileDialog::getOpenFileName( + this, tr("Select Image"), m_lineEdit->text(), tr("PNG (*.png)"))); + if (!file.isEmpty()) + { + m_lineEdit->setText(file); + } + } +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/FormImageBrowseEditWidget.h b/Code/Tools/ProjectManager/Source/FormImageBrowseEditWidget.h new file mode 100644 index 0000000000..e01e9254f8 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/FormImageBrowseEditWidget.h @@ -0,0 +1,33 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#pragma once + +#if !defined(Q_MOC_RUN) +#include +#endif + +namespace O3DE::ProjectManager +{ + class FormImageBrowseEditWidget + : public FormBrowseEditWidget + { + Q_OBJECT + + public: + explicit FormImageBrowseEditWidget(const QString& labelText, const QString& valueText = "", QWidget* parent = nullptr); + ~FormImageBrowseEditWidget() = default; + + protected: + void HandleBrowseButton() override; + }; +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp b/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp index 5faa6cb8bd..efe34f6fa6 100644 --- a/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp +++ b/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp @@ -12,8 +12,8 @@ #include #include -#include #include +#include #include #include #include diff --git a/Code/Tools/ProjectManager/Source/ProjectBuilder.cpp b/Code/Tools/ProjectManager/Source/ProjectBuilder.cpp index 8cdab93c6a..62f879963f 100644 --- a/Code/Tools/ProjectManager/Source/ProjectBuilder.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectBuilder.cpp @@ -11,6 +11,7 @@ */ #include +#include #include #include @@ -30,8 +31,6 @@ namespace O3DE::ProjectManager { // 10 Minutes constexpr int MaxBuildTimeMSecs = 600000; - static const QString BuildPathPostfix = "windows_vs2019"; - static const QString ErrorLogPathPostfix = "CMakeFiles/CMakeProjectBuildError.log"; ProjectBuilderWorker::ProjectBuilderWorker(const ProjectInfo& projectInfo) : QObject() @@ -83,7 +82,7 @@ namespace O3DE::ProjectManager QStringList { "-B", - QDir(m_projectInfo.m_path).filePath(BuildPathPostfix), + QDir(m_projectInfo.m_path).filePath(ProjectBuildPathPostfix), "-S", m_projectInfo.m_path, "-G", @@ -123,7 +122,7 @@ namespace O3DE::ProjectManager QStringList { "--build", - QDir(m_projectInfo.m_path).filePath(BuildPathPostfix), + QDir(m_projectInfo.m_path).filePath(ProjectBuildPathPostfix), "--target", m_projectInfo.m_projectName + ".GameLauncher", "Editor", @@ -159,8 +158,8 @@ namespace O3DE::ProjectManager QString ProjectBuilderWorker::LogFilePath() const { QDir logFilePath(m_projectInfo.m_path); - logFilePath.cd(BuildPathPostfix); - return logFilePath.filePath(ErrorLogPathPostfix); + logFilePath.cd(ProjectBuildPathPostfix); + return logFilePath.filePath(ProjectBuildErrorLogPathPostfix); } void ProjectBuilderWorker::WriteErrorLog(const QString& log) diff --git a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp index 3bde0a310d..aaf87fd9cf 100644 --- a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp @@ -11,6 +11,7 @@ */ #include +#include #include #include @@ -22,12 +23,11 @@ #include #include #include +#include +#include namespace O3DE::ProjectManager { - inline constexpr static int s_projectImageWidth = 210; - inline constexpr static int s_projectImageHeight = 280; - LabelButton::LabelButton(QWidget* parent) : QLabel(parent) { @@ -92,11 +92,6 @@ namespace O3DE::ProjectManager : QFrame(parent) , m_projectInfo(projectInfo) { - if (m_projectInfo.m_imagePath.isEmpty()) - { - m_projectInfo.m_imagePath = ":/DefaultProjectImage.png"; - } - BaseSetup(); if (processing) { @@ -118,20 +113,25 @@ namespace O3DE::ProjectManager setLayout(vLayout); m_projectImageLabel = new LabelButton(this); - m_projectImageLabel->setFixedSize(s_projectImageWidth, s_projectImageHeight); + m_projectImageLabel->setFixedSize(ProjectPreviewImageWidth, ProjectPreviewImageHeight); m_projectImageLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); connect(m_projectImageLabel, &LabelButton::triggered, [this]() { emit OpenProject(m_projectInfo.m_path); }); vLayout->addWidget(m_projectImageLabel); - m_projectImageLabel->setPixmap( - QPixmap(m_projectInfo.m_imagePath).scaled(m_projectImageLabel->size(), Qt::KeepAspectRatioByExpanding)); + QString projectPreviewPath = QDir(m_projectInfo.m_path).filePath(m_projectInfo.m_iconPath); + QFileInfo doesPreviewExist(projectPreviewPath); + if (!doesPreviewExist.exists() || !doesPreviewExist.isFile()) + { + projectPreviewPath = ":/DefaultProjectImage.png"; + } + m_projectImageLabel->setPixmap(QPixmap(projectPreviewPath).scaled(m_projectImageLabel->size(), Qt::KeepAspectRatioByExpanding)); m_projectFooter = new QFrame(this); QHBoxLayout* hLayout = new QHBoxLayout(); hLayout->setContentsMargins(0, 0, 0, 0); m_projectFooter->setLayout(hLayout); { - QLabel* projectNameLabel = new QLabel(m_projectInfo.m_displayName, this); + QLabel* projectNameLabel = new QLabel(m_projectInfo.GetProjectDisplayName(), this); hLayout->addWidget(projectNameLabel); } diff --git a/Code/Tools/ProjectManager/Source/ProjectInfo.cpp b/Code/Tools/ProjectManager/Source/ProjectInfo.cpp index 99649cbfdf..e7d8a6d0e7 100644 --- a/Code/Tools/ProjectManager/Source/ProjectInfo.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectInfo.cpp @@ -10,33 +10,74 @@ * */ -#include "ProjectInfo.h" +#include +#include + +#include namespace O3DE::ProjectManager { - ProjectInfo::ProjectInfo(const QString& path, const QString& projectName, const QString& displayName, - const QString& origin, const QString& summary, const QString& imagePath, const QString& backgroundImagePath, + ProjectInfo::ProjectInfo( + const QString& path, + const QString& projectName, + const QString& displayName, + const QString& origin, + const QString& summary, + const QString& iconPath, + const QString& newPreviewImagePath, + const QString& newBackgroundImagePath, bool needsBuild) : m_path(path) , m_projectName(projectName) , m_displayName(displayName) , m_origin(origin) , m_summary(summary) - , m_imagePath(imagePath) - , m_backgroundImagePath(backgroundImagePath) + , m_iconPath(iconPath) + , m_newPreviewImagePath(newPreviewImagePath) + , m_newBackgroundImagePath(newBackgroundImagePath) , m_needsBuild(needsBuild) { } - bool ProjectInfo::operator==(const ProjectInfo& rhs) + bool ProjectInfo::operator==(const ProjectInfo& rhs) const { - return m_path == rhs.m_path - && m_projectName == rhs.m_projectName - && m_imagePath == rhs.m_imagePath - && m_backgroundImagePath == rhs.m_backgroundImagePath; + if (m_path != rhs.m_path) + { + return false; + } + if (m_projectName != rhs.m_projectName) + { + return false; + } + if (m_displayName != rhs.m_displayName) + { + return false; + } + if (m_origin != rhs.m_origin) + { + return false; + } + if (m_summary != rhs.m_summary) + { + return false; + } + if (m_iconPath != rhs.m_iconPath) + { + return false; + } + if (m_newPreviewImagePath != rhs.m_newPreviewImagePath) + { + return false; + } + if (m_newBackgroundImagePath != rhs.m_newBackgroundImagePath) + { + return false; + } + + return true; } - bool ProjectInfo::operator!=(const ProjectInfo& rhs) + bool ProjectInfo::operator!=(const ProjectInfo& rhs) const { return !operator==(rhs); } @@ -45,4 +86,16 @@ namespace O3DE::ProjectManager { return !m_path.isEmpty() && !m_projectName.isEmpty(); } + + const QString& ProjectInfo::GetProjectDisplayName() const + { + if (!m_displayName.isEmpty()) + { + return m_displayName; + } + else + { + return m_projectName; + } + } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectInfo.h b/Code/Tools/ProjectManager/Source/ProjectInfo.h index 184916a514..72f64408f4 100644 --- a/Code/Tools/ProjectManager/Source/ProjectInfo.h +++ b/Code/Tools/ProjectManager/Source/ProjectInfo.h @@ -31,14 +31,16 @@ namespace O3DE::ProjectManager const QString& displayName, const QString& origin, const QString& summary, - const QString& imagePath, - const QString& backgroundImagePath, + const QString& iconPath, + const QString& newPreviewImagePath, + const QString& newBackgroundImagePath, bool needsBuild); - bool operator==(const ProjectInfo& rhs); - bool operator!=(const ProjectInfo& rhs); + bool operator==(const ProjectInfo& rhs) const; + bool operator!=(const ProjectInfo& rhs) const; bool IsValid() const; + const QString& GetProjectDisplayName() const; // from o3de_manifest.json and o3de_projects.json QString m_path; @@ -48,14 +50,14 @@ namespace O3DE::ProjectManager QString m_displayName; QString m_origin; QString m_summary; + QString m_iconPath; QStringList m_userTags; - // Used on projects home screen - QString m_imagePath; - QString m_backgroundImagePath; + // Used as temp variable for replace images + QString m_newPreviewImagePath; + QString m_newBackgroundImagePath; // Used in project creation - bool m_needsBuild = false; //! Does this project need to be built }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h b/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h new file mode 100644 index 0000000000..eafab28a60 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h @@ -0,0 +1,24 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ +#pragma once + +#include + +namespace O3DE::ProjectManager +{ + inline constexpr static int ProjectPreviewImageWidth = 210; + inline constexpr static int ProjectPreviewImageHeight = 280; + + static const QString ProjectBuildPathPostfix = "Windows_VS2019"; + static const QString ProjectBuildErrorLogPathPostfix = "CMakeFiles/CMakeProjectBuildError.log"; + static const QString ProjectPreviewImagePath = "preview.png"; +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.cpp b/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.cpp index b198724353..9dbbf26aa4 100644 --- a/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.cpp @@ -11,7 +11,7 @@ */ #include -#include +#include #include #include #include @@ -47,7 +47,7 @@ namespace O3DE::ProjectManager connect(m_projectName->lineEdit(), &QLineEdit::textChanged, this, &ProjectSettingsScreen::ValidateProjectName); m_verticalLayout->addWidget(m_projectName); - m_projectPath = new FormBrowseEditWidget(tr("Project Location"), "", this); + m_projectPath = new FormFolderBrowseEditWidget(tr("Project Location"), "", this); m_projectPath->lineEdit()->setReadOnly(true); connect(m_projectPath->lineEdit(), &QLineEdit::textChanged, this, &ProjectSettingsScreen::Validate); m_verticalLayout->addWidget(m_projectPath); diff --git a/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.h b/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.h index 0d75bbbc64..1b1f03051d 100644 --- a/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.h +++ b/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.h @@ -32,9 +32,9 @@ namespace O3DE::ProjectManager ~ProjectSettingsScreen() = default; ProjectManagerScreen GetScreenEnum() override; - ProjectInfo GetProjectInfo(); + virtual ProjectInfo GetProjectInfo(); - bool Validate(); + virtual bool Validate(); protected slots: virtual bool ValidateProjectName(); diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp index 3e2b3c13e1..91e7f0a719 100644 --- a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp @@ -29,11 +29,8 @@ namespace O3DE::ProjectManager if (!QDir(path).isEmpty()) { QMessageBox::StandardButton warningResult = QMessageBox::warning( - parent, - QObject::tr("Overwrite Directory"), - QObject::tr("Directory is not empty! Are you sure you want to overwrite it?"), - QMessageBox::No | QMessageBox::Yes - ); + parent, QObject::tr("Overwrite Directory"), + QObject::tr("Directory is not empty! Are you sure you want to overwrite it?"), QMessageBox::No | QMessageBox::Yes); if (warningResult != QMessageBox::Yes) { @@ -53,14 +50,13 @@ namespace O3DE::ProjectManager { if (ancestor == descendent) { - return false; + return true; } descendent.cdUp(); - } - while (!descendent.isRoot()); + } while (!descendent.isRoot()); - return true; + return false; } static bool CopyDirectory(const QString& origPath, const QString& newPath) @@ -138,7 +134,7 @@ namespace O3DE::ProjectManager bool CopyProject(const QString& origPath, const QString& newPath) { // Disallow copying from or into subdirectory - if (!IsDirectoryDescedent(origPath, newPath) || !IsDirectoryDescedent(newPath, origPath)) + if (IsDirectoryDescedent(origPath, newPath) || IsDirectoryDescedent(newPath, origPath)) { return false; } @@ -173,20 +169,66 @@ namespace O3DE::ProjectManager return false; } - bool MoveProject(const QString& origPath, const QString& newPath, QWidget* parent) + bool MoveProject(QString origPath, QString newPath, QWidget* parent, bool ignoreRegister) { - if (!WarnDirectoryOverwrite(newPath, parent) || !UnregisterProject(origPath)) + origPath = QDir::toNativeSeparators(origPath); + newPath = QDir::toNativeSeparators(newPath); + + if (!WarnDirectoryOverwrite(newPath, parent) || (!ignoreRegister && !UnregisterProject(origPath))) { return false; } - QDir directory; - if (directory.rename(origPath, newPath)) + QDir newDirectory(newPath); + if (!newDirectory.removeRecursively()) { - return directory.rename(origPath, newPath); + return false; + } + if (!newDirectory.rename(origPath, newPath)) + { + // Likely failed because trying to move to another partition, try copying + if (!CopyProject(origPath, newPath)) + { + return false; + } + + DeleteProjectFiles(origPath, true); } - if (!RegisterProject(newPath)) + if (!ignoreRegister && !RegisterProject(newPath)) + { + return false; + } + + return true; + } + + bool ReplaceFile(const QString& origFile, const QString& newFile, QWidget* parent, bool interactive) + { + QFileInfo original(origFile); + if (original.exists()) + { + if (interactive) + { + QMessageBox::StandardButton warningResult = QMessageBox::warning( + parent, + QObject::tr("Overwrite File?"), + QObject::tr("Replacing this will overwrite the current file on disk. Are you sure?"), + QMessageBox::No | QMessageBox::Yes); + + if (warningResult == QMessageBox::No) + { + return false; + } + } + + if (!QFile::remove(origFile)) + { + return false; + } + } + + if (!QFile::copy(newFile, origFile)) { return false; } diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.h b/Code/Tools/ProjectManager/Source/ProjectUtils.h index 9c711ad187..2fa1258e8f 100644 --- a/Code/Tools/ProjectManager/Source/ProjectUtils.h +++ b/Code/Tools/ProjectManager/Source/ProjectUtils.h @@ -24,7 +24,9 @@ namespace O3DE::ProjectManager bool CopyProjectDialog(const QString& origPath, QWidget* parent = nullptr); bool CopyProject(const QString& origPath, const QString& newPath); bool DeleteProjectFiles(const QString& path, bool force = false); - bool MoveProject(const QString& origPath, const QString& newPath, QWidget* parent = nullptr); + bool MoveProject(QString origPath, QString newPath, QWidget* parent = nullptr, bool ignoreRegister = false); + + bool ReplaceFile(const QString& origFile, const QString& newFile, QWidget* parent = nullptr, bool interactive = true); bool IsVS2019Installed(); diff --git a/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp b/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp index 6633558406..d0534c1e76 100644 --- a/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp @@ -12,6 +12,7 @@ #include +#include #include #include #include @@ -35,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -218,16 +218,7 @@ namespace O3DE::ProjectManager ProjectButton* ProjectsScreen::CreateProjectButton(ProjectInfo& project, QLayout* flowLayout, bool processing) { - ProjectButton* projectButton; - - QString projectPreviewPath = project.m_path + m_projectPreviewImagePath; - QFileInfo doesPreviewExist(projectPreviewPath); - if (doesPreviewExist.exists() && doesPreviewExist.isFile()) - { - project.m_imagePath = projectPreviewPath; - } - - projectButton = new ProjectButton(project, this, processing); + ProjectButton* projectButton = new ProjectButton(project, this, processing); flowLayout->addWidget(projectButton); @@ -438,7 +429,7 @@ namespace O3DE::ProjectManager { QMessageBox::information(this, tr("Project Should be rebuilt."), - projectInfo.m_projectName + tr(" project likely needs to be rebuilt.")); + projectInfo.GetProjectDisplayName() + tr(" project likely needs to be rebuilt.")); } } @@ -499,8 +490,8 @@ namespace O3DE::ProjectManager { QMessageBox::StandardButton buildProject = QMessageBox::information( this, - tr("Building \"%1\"").arg(projectInfo.m_projectName), - tr("Ready to build \"%1\"?").arg(projectInfo.m_projectName), + tr("Building \"%1\"").arg(projectInfo.GetProjectDisplayName()), + tr("Ready to build \"%1\"?").arg(projectInfo.GetProjectDisplayName()), QMessageBox::No | QMessageBox::Yes); if (buildProject == QMessageBox::Yes) diff --git a/Code/Tools/ProjectManager/Source/ProjectsScreen.h b/Code/Tools/ProjectManager/Source/ProjectsScreen.h index bc28d4ef30..b86c2b0240 100644 --- a/Code/Tools/ProjectManager/Source/ProjectsScreen.h +++ b/Code/Tools/ProjectManager/Source/ProjectsScreen.h @@ -80,8 +80,6 @@ namespace O3DE::ProjectManager QQueue m_buildQueue; ProjectBuilderController* m_currentBuilder = nullptr; - const QString m_projectPreviewImagePath = "/preview.png"; - inline constexpr static int s_contentMargins = 80; inline constexpr static int s_spacerSize = 20; }; diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 0e00319b6b..993c0abeaa 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -12,6 +12,7 @@ #include +#include // Qt defines slots, which interferes with the use here. #pragma push_macro("slots") @@ -693,6 +694,7 @@ namespace O3DE::ProjectManager projectInfo.m_displayName = Py_To_String_Optional(projectData, "display_name", projectInfo.m_projectName); projectInfo.m_origin = Py_To_String_Optional(projectData, "origin", projectInfo.m_origin); projectInfo.m_summary = Py_To_String_Optional(projectData, "summary", projectInfo.m_summary); + projectInfo.m_iconPath = Py_To_String_Optional(projectData, "icon", ProjectPreviewImagePath); if (projectData.contains("user_tags")) { for (auto tag : projectData["user_tags"]) @@ -786,7 +788,7 @@ namespace O3DE::ProjectManager pybind11::str(projectInfo.m_origin.toStdString()), // new_origin pybind11::str(projectInfo.m_displayName.toStdString()), // new_display pybind11::str(projectInfo.m_summary.toStdString()), // new_summary - pybind11::str(projectInfo.m_imagePath.toStdString()), // new_icon + pybind11::str(projectInfo.m_iconPath.toStdString()), // new_icon pybind11::none(), // add_tags not used pybind11::none(), // remove_tags not used pybind11::list(pybind11::cast(newTags))); // replace_tags diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp index 409c51315d..f5414a67a1 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -24,6 +25,7 @@ #include #include #include +#include namespace O3DE::ProjectManager { @@ -101,8 +103,11 @@ namespace O3DE::ProjectManager void UpdateProjectCtrl::HandleGemsButton() { - m_stack->setCurrentWidget(m_gemCatalogScreen); - Update(); + if (UpdateProjectSettings(true)) + { + m_stack->setCurrentWidget(m_gemCatalogScreen); + Update(); + } } void UpdateProjectCtrl::HandleBackButton() @@ -114,7 +119,10 @@ namespace O3DE::ProjectManager } else { - emit GotoPreviousScreenRequest(); + if (UpdateProjectSettings(true)) + { + emit GotoPreviousScreenRequest(); + } } } @@ -124,38 +132,9 @@ namespace O3DE::ProjectManager if (m_stack->currentIndex() == ScreenOrder::Settings && m_updateSettingsScreen) { - if (m_updateSettingsScreen) + if (!UpdateProjectSettings()) { - if (!m_updateSettingsScreen->Validate()) - { - QMessageBox::critical(this, tr("Invalid project settings"), tr("Invalid project settings")); - return; - } - - ProjectInfo newProjectSettings = m_updateSettingsScreen->GetProjectInfo(); - - // Update project if settings changed - if (m_projectInfo != newProjectSettings) - { - auto result = PythonBindingsInterface::Get()->UpdateProject(newProjectSettings); - if (!result.IsSuccess()) - { - QMessageBox::critical(this, tr("Project update failed"), tr(result.GetError().c_str())); - return; - } - } - - // Check if project path has changed and move it - if (newProjectSettings.m_path != m_projectInfo.m_path) - { - if (!ProjectUtils::MoveProject(m_projectInfo.m_path, newProjectSettings.m_path)) - { - QMessageBox::critical(this, tr("Project move failed"), tr("Failed to move project.")); - return; - } - } - - m_projectInfo = newProjectSettings; + return; } } else if (m_stack->currentIndex() == ScreenOrder::Gems && m_gemCatalogScreen) @@ -190,14 +169,15 @@ namespace O3DE::ProjectManager { if (m_stack->currentIndex() == ScreenOrder::Gems) { - m_header->setTitle(QString(tr("Edit Project Settings: \"%1\"")).arg(m_projectInfo.m_projectName)); + + m_header->setTitle(QString(tr("Edit Project Settings: \"%1\"")).arg(m_projectInfo.GetProjectDisplayName())); m_header->setSubTitle(QString(tr("Configure Gems"))); - m_nextButton->setText(tr("Finalize")); + m_nextButton->setText(tr("Save")); } else { m_header->setTitle(""); - m_header->setSubTitle(QString(tr("Edit Project Settings: \"%1\"")).arg(m_projectInfo.m_projectName)); + m_header->setSubTitle(QString(tr("Edit Project Settings: \"%1\"")).arg(m_projectInfo.GetProjectDisplayName())); m_nextButton->setText(tr("Save")); } } @@ -207,4 +187,70 @@ namespace O3DE::ProjectManager m_updateSettingsScreen->SetProjectInfo(m_projectInfo); } + bool UpdateProjectCtrl::UpdateProjectSettings(bool shouldConfirm) + { + AZ_Assert(m_updateSettingsScreen, "Update settings screen is nullptr.") + + ProjectInfo newProjectSettings = m_updateSettingsScreen->GetProjectInfo(); + + if (m_projectInfo != newProjectSettings) + { + if (shouldConfirm) + { + QMessageBox::StandardButton warningResult = QMessageBox::warning( + this, + QObject::tr("Unsaved Changes!"), + QObject::tr("Would you like to save your changes to project settings?"), + QMessageBox::No | QMessageBox::Yes + ); + + if (warningResult == QMessageBox::No) + { + return true; + } + } + + if (!m_updateSettingsScreen->Validate()) + { + QMessageBox::critical(this, tr("Invalid project settings"), tr("Invalid project settings")); + return false; + } + + // Update project if settings changed + { + auto result = PythonBindingsInterface::Get()->UpdateProject(newProjectSettings); + if (!result.IsSuccess()) + { + QMessageBox::critical(this, tr("Project update failed"), tr(result.GetError().c_str())); + return false; + } + } + + // Check if project path has changed and move it + if (newProjectSettings.m_path != m_projectInfo.m_path) + { + if (!ProjectUtils::MoveProject(m_projectInfo.m_path, newProjectSettings.m_path)) + { + QMessageBox::critical(this, tr("Project move failed"), tr("Failed to move project.")); + return false; + } + } + + if (!newProjectSettings.m_newPreviewImagePath.isEmpty()) + { + if (!ProjectUtils::ReplaceFile( + QDir(newProjectSettings.m_path).filePath(newProjectSettings.m_iconPath), newProjectSettings.m_newPreviewImagePath)) + { + QMessageBox::critical(this, tr("File replace failed"), tr("Failed to replace project preview image.")); + return false; + } + m_updateSettingsScreen->ResetProjectPreviewPath(); + } + + m_projectInfo = newProjectSettings; + } + + return true; + } + } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h index 231bfb8f19..b8b57c0c20 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h +++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h @@ -46,6 +46,7 @@ namespace O3DE::ProjectManager private: void Update(); void UpdateSettingsScreen(); + bool UpdateProjectSettings(bool shouldConfirm = false); enum ScreenOrder { diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.cpp b/Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.cpp index c29be3c7fd..f7be7e84c3 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.cpp +++ b/Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.cpp @@ -11,17 +11,43 @@ */ #include -#include +#include +#include #include +#include #include #include +#include +#include namespace O3DE::ProjectManager { UpdateProjectSettingsScreen::UpdateProjectSettingsScreen(QWidget* parent) : ProjectSettingsScreen(parent) + , m_userChangedPreview(false) { + m_projectPreview = new FormImageBrowseEditWidget(tr("Project Preview"), "", this); + m_projectPreview->lineEdit()->setReadOnly(true); + connect(m_projectPreview->lineEdit(), &QLineEdit::textChanged, this, &ProjectSettingsScreen::Validate); + connect(m_projectPreview->lineEdit(), &QLineEdit::textChanged, this, &UpdateProjectSettingsScreen::PreviewPathChanged); + connect(m_projectPath->lineEdit(), &QLineEdit::textChanged, this, &UpdateProjectSettingsScreen::UpdateProjectPreviewPath); + m_verticalLayout->addWidget(m_projectPreview); + + QVBoxLayout* previewExtrasLayout = new QVBoxLayout(this); + previewExtrasLayout->setAlignment(Qt::AlignLeft); + previewExtrasLayout->setContentsMargins(50, 0, 0, 0); + + QLabel* projectPreviewLabel = new QLabel(tr("Select an image (PNG). Minimum %1 x %2 pixels.") + .arg(QString::number(ProjectPreviewImageWidth), QString::number(ProjectPreviewImageHeight))); + previewExtrasLayout->addWidget(projectPreviewLabel); + + m_projectPreviewImage = new QLabel(this); + m_projectPreviewImage->setFixedSize(ProjectPreviewImageWidth, ProjectPreviewImageHeight); + m_projectPreviewImage->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + previewExtrasLayout->addWidget(m_projectPreviewImage); + + m_verticalLayout->addLayout(previewExtrasLayout); } ProjectManagerScreen UpdateProjectSettingsScreen::GetScreenEnum() @@ -29,10 +55,58 @@ namespace O3DE::ProjectManager return ProjectManagerScreen::UpdateProjectSettings; } + ProjectInfo UpdateProjectSettingsScreen::GetProjectInfo() + { + m_projectInfo.m_displayName = m_projectName->lineEdit()->text(); + m_projectInfo.m_path = m_projectPath->lineEdit()->text(); + + if (m_userChangedPreview) + { + m_projectInfo.m_iconPath = ProjectPreviewImagePath; + m_projectInfo.m_newPreviewImagePath = m_projectPreview->lineEdit()->text(); + } + return m_projectInfo; + } + void UpdateProjectSettingsScreen::SetProjectInfo(const ProjectInfo& projectInfo) { - m_projectName->lineEdit()->setText(projectInfo.m_projectName); + m_projectInfo = projectInfo; + + m_projectName->lineEdit()->setText(projectInfo.GetProjectDisplayName()); + m_projectPath->lineEdit()->setText(projectInfo.m_path); + UpdateProjectPreviewPath(); + } + + void UpdateProjectSettingsScreen::UpdateProjectPreviewPath() + { + if (!m_userChangedPreview) + { + m_projectPreview->lineEdit()->setText(QDir(m_projectPath->lineEdit()->text()).filePath(m_projectInfo.m_iconPath)); + // Setting the text sets m_userChangedPreview to true + // Set it back to false because it should only be true when changed by user + m_userChangedPreview = false; + } + } + + bool UpdateProjectSettingsScreen::Validate() + { + return ProjectSettingsScreen::Validate() && ValidateProjectPreview(); + } + + void UpdateProjectSettingsScreen::ResetProjectPreviewPath() + { + m_userChangedPreview = false; + UpdateProjectPreviewPath(); + } + + void UpdateProjectSettingsScreen::PreviewPathChanged() + { + m_userChangedPreview = true; + + // Update with latest image + m_projectPreviewImage->setPixmap( + QPixmap(m_projectPreview->lineEdit()->text()).scaled(m_projectPreviewImage->size(), Qt::KeepAspectRatioByExpanding)); } bool UpdateProjectSettingsScreen::ValidateProjectPath() @@ -48,4 +122,39 @@ namespace O3DE::ProjectManager return projectPathIsValid; } + bool UpdateProjectSettingsScreen::ValidateProjectPreview() + { + bool projectPreviewIsValid = true; + + if (m_projectPreview->lineEdit()->text().isEmpty()) + { + projectPreviewIsValid = false; + m_projectPreview->setErrorLabelText(tr("Please select a file.")); + } + else + { + if (m_userChangedPreview) + { + QFileInfo previewFile(m_projectPreview->lineEdit()->text()); + if (!previewFile.exists() || !previewFile.isFile()) + { + projectPreviewIsValid = false; + m_projectPreview->setErrorLabelText(tr("Please select a valid png file.")); + } + else + { + QString fileType = previewFile.completeSuffix().toLower(); + if (fileType != "png") + { + projectPreviewIsValid = false; + m_projectPreview->setErrorLabelText(tr("Please select a png image.")); + } + } + } + } + + m_projectPreview->setErrorLabelVisible(!projectPreviewIsValid); + return projectPreviewIsValid; + } + } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.h b/Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.h index 95bbceb9c6..1961648b5b 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.h +++ b/Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.h @@ -15,6 +15,8 @@ #include #endif +QT_FORWARD_DECLARE_CLASS(QLabel) + namespace O3DE::ProjectManager { class UpdateProjectSettingsScreen @@ -25,10 +27,26 @@ namespace O3DE::ProjectManager ~UpdateProjectSettingsScreen() = default; ProjectManagerScreen GetScreenEnum() override; + ProjectInfo GetProjectInfo() override; void SetProjectInfo(const ProjectInfo& projectInfo); + bool Validate() override; + + void ResetProjectPreviewPath(); + + public slots: + void UpdateProjectPreviewPath(); + void PreviewPathChanged(); + protected: bool ValidateProjectPath() override; + virtual bool ValidateProjectPreview(); + + FormBrowseEditWidget* m_projectPreview; + QLabel* m_projectPreviewImage; + + ProjectInfo m_projectInfo; + bool m_userChangedPreview; //! Did the user change the project preview path }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake index 587b5907bb..8e4c4cd321 100644 --- a/Code/Tools/ProjectManager/project_manager_files.cmake +++ b/Code/Tools/ProjectManager/project_manager_files.cmake @@ -13,6 +13,7 @@ set(FILES Source/Application.h Source/Application.cpp + Source/ProjectManagerDefs.h Source/ScreenDefs.h Source/ScreenFactory.h Source/ScreenFactory.cpp @@ -25,6 +26,10 @@ set(FILES Source/FormLineEditWidget.cpp Source/FormBrowseEditWidget.h Source/FormBrowseEditWidget.cpp + Source/FormFolderBrowseEditWidget.h + Source/FormFolderBrowseEditWidget.cpp + Source/FormImageBrowseEditWidget.h + Source/FormImageBrowseEditWidget.cpp Source/PathValidator.h Source/PathValidator.cpp Source/ProjectManagerWindow.h diff --git a/Code/Tools/ProjectManager/project_manager_tests_files.cmake b/Code/Tools/ProjectManager/project_manager_tests_files.cmake index e1e84a43a7..e340469bcc 100644 --- a/Code/Tools/ProjectManager/project_manager_tests_files.cmake +++ b/Code/Tools/ProjectManager/project_manager_tests_files.cmake @@ -14,4 +14,5 @@ set(FILES Resources/ProjectManager.qss tests/ApplicationTests.cpp tests/main.cpp + tests/UtilsTests.cpp ) diff --git a/Code/Tools/ProjectManager/tests/UtilsTests.cpp b/Code/Tools/ProjectManager/tests/UtilsTests.cpp new file mode 100644 index 0000000000..e248d37bee --- /dev/null +++ b/Code/Tools/ProjectManager/tests/UtilsTests.cpp @@ -0,0 +1,120 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace O3DE::ProjectManager +{ + namespace ProjectUtils + { + class ProjectManagerUtilsTests + : public ::UnitTest::ScopedAllocatorSetupFixture + { + public: + ProjectManagerUtilsTests() + { + m_application = AZStd::make_unique(); + m_application->Init(false); + + QDir dir; + dir.mkdir("ProjectA"); + dir.mkdir("ProjectB"); + + QFile origFile("ProjectA/origFile.txt"); + if (origFile.open(QIODevice::ReadWrite)) + { + QTextStream stream(&origFile); + stream << "orig" << Qt::endl; + origFile.close(); + } + + QFile replaceFile("ProjectA/replaceFile.txt"); + if (replaceFile.open(QIODevice::ReadWrite)) + { + QTextStream stream(&replaceFile); + stream << "replace" << Qt::endl; + replaceFile.close(); + } + } + + ~ProjectManagerUtilsTests() + { + QDir dirA("ProjectA"); + dirA.removeRecursively(); + + QDir dirB("ProjectB"); + dirB.removeRecursively(); + + m_application.reset(); + } + + AZStd::unique_ptr m_application; + }; + +#if AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS + TEST_F(ProjectManagerUtilsTests, DISABLED_MoveProject_Succeeds) +#else + TEST_F(ProjectManagerUtilsTests, MoveProject_Succeeds) +#endif // !AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS + { + EXPECT_TRUE(MoveProject( + QDir::currentPath() + QDir::separator() + "ProjectA", + QDir::currentPath() + QDir::separator() + "ProjectB", + nullptr, true)); + + QFileInfo origFile("ProjectA/origFile.txt"); + EXPECT_TRUE(!origFile.exists()); + + QFileInfo replaceFile("ProjectA/replaceFile.txt"); + EXPECT_TRUE(!replaceFile.exists()); + + QFileInfo origFileMoved("ProjectB/origFile.txt"); + EXPECT_TRUE(origFileMoved.exists() && origFileMoved.isFile()); + + QFileInfo replaceFileMoved("ProjectB/replaceFile.txt"); + EXPECT_TRUE(replaceFileMoved.exists() && replaceFileMoved.isFile()); + } + +#if AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS + TEST_F(ProjectManagerUtilsTests, DISABLED_ReplaceFile_Succeeds) +#else + TEST_F(ProjectManagerUtilsTests, ReplaceFile_Succeeds) +#endif // !AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS + { + EXPECT_TRUE(ReplaceFile("ProjectA/origFile.txt", "ProjectA/replaceFile.txt", nullptr, false)); + + QFile origFile("ProjectA/origFile.txt"); + if (origFile.open(QIODevice::ReadOnly)) + { + QTextStream stream(&origFile); + QString line = stream.readLine(); + EXPECT_EQ(line, "replace"); + + origFile.close(); + } + else + { + FAIL(); + } + } + } // namespace ProjectUtils +} // namespace O3DE::ProjectManager