Project Manager Build Project from Projects Page (#1142)
* Added loading bar mode to project button * Added ProjectBuilder files * commmit current progress for project building * Push current project building work * Full build commands built out and message boxes for lots of situation * Replaced defaultProjectImage placeholder * Added installed cmake path to builder process env PATH
This commit is contained in:
@@ -206,6 +206,8 @@ namespace O3DE::ProjectManager
|
||||
m_gemCatalogScreen->EnableDisableGemsForProject(projectInfo.m_path);
|
||||
#endif // TEMPLATE_GEM_CONFIGURATION_ENABLED
|
||||
|
||||
projectInfo.m_needsBuild = true;
|
||||
emit NotifyBuildProject(projectInfo);
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::Projects);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* 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 <ProjectBuilder.h>
|
||||
#include <ProjectButtonWidget.h>
|
||||
#include <PythonBindingsInterface.h>
|
||||
|
||||
#include <QProcess>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QMessageBox>
|
||||
#include <QDesktopServices>
|
||||
#include <QUrl>
|
||||
#include <QDir>
|
||||
#include <QProcessEnvironment>
|
||||
|
||||
|
||||
//#define MOCK_BUILD_PROJECT true
|
||||
|
||||
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()
|
||||
, m_projectInfo(projectInfo)
|
||||
{
|
||||
}
|
||||
|
||||
void ProjectBuilderWorker::BuildProject()
|
||||
{
|
||||
#ifdef MOCK_BUILD_PROJECT
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
QThread::sleep(1);
|
||||
UpdateProgress(i * 10);
|
||||
}
|
||||
Done(m_projectPath);
|
||||
#else
|
||||
EngineInfo engineInfo;
|
||||
|
||||
AZ::Outcome<EngineInfo> engineInfoResult = PythonBindingsInterface::Get()->GetEngineInfo();
|
||||
if (engineInfoResult.IsSuccess())
|
||||
{
|
||||
engineInfo = engineInfoResult.GetValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
emit Done(tr("Failed to get engine info."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Show some kind of progress with very approximate estimates
|
||||
UpdateProgress(1);
|
||||
|
||||
QProcessEnvironment currentEnvironment(QProcessEnvironment::systemEnvironment());
|
||||
// Append cmake path to PATH incase it is missing
|
||||
QDir cmakePath(engineInfo.m_path);
|
||||
cmakePath.cd("cmake/runtime/bin");
|
||||
QString pathValue = currentEnvironment.value("PATH");
|
||||
pathValue += ";" + cmakePath.path();
|
||||
currentEnvironment.insert("PATH", pathValue);
|
||||
|
||||
QProcess configProjectProcess;
|
||||
configProjectProcess.setProcessChannelMode(QProcess::MergedChannels);
|
||||
configProjectProcess.setWorkingDirectory(m_projectInfo.m_path);
|
||||
configProjectProcess.setProcessEnvironment(currentEnvironment);
|
||||
|
||||
configProjectProcess.start(
|
||||
"cmake",
|
||||
QStringList
|
||||
{
|
||||
"-B",
|
||||
QDir(m_projectInfo.m_path).filePath(BuildPathPostfix),
|
||||
"-S",
|
||||
m_projectInfo.m_path,
|
||||
"-G",
|
||||
"Visual Studio 16",
|
||||
"-DLY_3RDPARTY_PATH=" + engineInfo.m_thirdPartyPath
|
||||
});
|
||||
|
||||
if (!configProjectProcess.waitForStarted())
|
||||
{
|
||||
emit Done(tr("Configuring project failed to start."));
|
||||
return;
|
||||
}
|
||||
if (!configProjectProcess.waitForFinished(MaxBuildTimeMSecs))
|
||||
{
|
||||
WriteErrorLog(configProjectProcess.readAllStandardOutput());
|
||||
emit Done(tr("Configuring project timed out. See log for details"));
|
||||
return;
|
||||
}
|
||||
|
||||
QString configProjectOutput(configProjectProcess.readAllStandardOutput());
|
||||
if (configProjectProcess.exitCode() != 0 || !configProjectOutput.contains("Generating done"))
|
||||
{
|
||||
WriteErrorLog(configProjectOutput);
|
||||
emit Done(tr("Configuring project failed. See log for details."));
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateProgress(20);
|
||||
|
||||
QProcess buildProjectProcess;
|
||||
buildProjectProcess.setProcessChannelMode(QProcess::MergedChannels);
|
||||
buildProjectProcess.setWorkingDirectory(m_projectInfo.m_path);
|
||||
buildProjectProcess.setProcessEnvironment(currentEnvironment);
|
||||
|
||||
buildProjectProcess.start(
|
||||
"cmake",
|
||||
QStringList
|
||||
{
|
||||
"--build",
|
||||
QDir(m_projectInfo.m_path).filePath(BuildPathPostfix),
|
||||
"--target",
|
||||
m_projectInfo.m_projectName + ".GameLauncher",
|
||||
"Editor",
|
||||
"--config",
|
||||
"profile"
|
||||
});
|
||||
|
||||
if (!buildProjectProcess.waitForStarted())
|
||||
{
|
||||
emit Done(tr("Building project failed to start."));
|
||||
return;
|
||||
}
|
||||
if (!buildProjectProcess.waitForFinished(MaxBuildTimeMSecs))
|
||||
{
|
||||
WriteErrorLog(configProjectProcess.readAllStandardOutput());
|
||||
emit Done(tr("Building project timed out. See log for details"));
|
||||
return;
|
||||
}
|
||||
|
||||
QString buildProjectOutput(buildProjectProcess.readAllStandardOutput());
|
||||
if (configProjectProcess.exitCode() != 0)
|
||||
{
|
||||
WriteErrorLog(buildProjectOutput);
|
||||
emit Done(tr("Building project failed. See log for details."));
|
||||
}
|
||||
else
|
||||
{
|
||||
emit Done("");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
QString ProjectBuilderWorker::LogFilePath() const
|
||||
{
|
||||
QDir logFilePath(m_projectInfo.m_path);
|
||||
logFilePath.cd(BuildPathPostfix);
|
||||
return logFilePath.filePath(ErrorLogPathPostfix);
|
||||
}
|
||||
|
||||
void ProjectBuilderWorker::WriteErrorLog(const QString& log)
|
||||
{
|
||||
QFile logFile(LogFilePath());
|
||||
// Overwrite file with truncate
|
||||
if (logFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
|
||||
{
|
||||
QTextStream output(&logFile);
|
||||
output << log;
|
||||
logFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
ProjectBuilderController::ProjectBuilderController(const ProjectInfo& projectInfo, ProjectButton* projectButton, QWidget* parent)
|
||||
: QObject()
|
||||
, m_projectInfo(projectInfo)
|
||||
, m_projectButton(projectButton)
|
||||
, m_parent(parent)
|
||||
{
|
||||
m_worker = new ProjectBuilderWorker(m_projectInfo);
|
||||
m_worker->moveToThread(&m_workerThread);
|
||||
|
||||
connect(&m_workerThread, &QThread::finished, m_worker, &ProjectBuilderWorker::deleteLater);
|
||||
connect(&m_workerThread, &QThread::started, m_worker, &ProjectBuilderWorker::BuildProject);
|
||||
connect(m_worker, &ProjectBuilderWorker::Done, this, &ProjectBuilderController::HandleResults);
|
||||
connect(m_worker, &ProjectBuilderWorker::UpdateProgress, this, &ProjectBuilderController::UpdateUIProgress);
|
||||
}
|
||||
|
||||
ProjectBuilderController::~ProjectBuilderController()
|
||||
{
|
||||
m_workerThread.quit();
|
||||
m_workerThread.wait();
|
||||
}
|
||||
|
||||
void ProjectBuilderController::Start()
|
||||
{
|
||||
m_workerThread.start();
|
||||
UpdateUIProgress(0);
|
||||
}
|
||||
|
||||
void ProjectBuilderController::SetProjectButton(ProjectButton* projectButton)
|
||||
{
|
||||
m_projectButton = projectButton;
|
||||
}
|
||||
|
||||
QString ProjectBuilderController::GetProjectPath() const
|
||||
{
|
||||
return m_projectInfo.m_path;
|
||||
}
|
||||
|
||||
void ProjectBuilderController::UpdateUIProgress(int progress)
|
||||
{
|
||||
if (m_projectButton)
|
||||
{
|
||||
m_projectButton->SetButtonOverlayText(QString("%1 (%2%)\n\n").arg(tr("Building Project..."), QString::number(progress)));
|
||||
m_projectButton->SetProgressBarValue(progress);
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectBuilderController::HandleResults(const QString& result)
|
||||
{
|
||||
if (!result.isEmpty())
|
||||
{
|
||||
if (result.contains(tr("log")))
|
||||
{
|
||||
QMessageBox::StandardButton openLog = QMessageBox::critical(
|
||||
m_parent,
|
||||
tr("Project Failed to Build!"),
|
||||
result + tr("\n\nWould you like to view log?"),
|
||||
QMessageBox::No | QMessageBox::Yes);
|
||||
|
||||
if (openLog == QMessageBox::Yes)
|
||||
{
|
||||
// Open application assigned to this file type
|
||||
QDesktopServices::openUrl(QUrl("file:///" + m_worker->LogFilePath()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(m_parent, tr("Project Failed to Build!"), result);
|
||||
}
|
||||
}
|
||||
|
||||
emit Done();
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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 <ProjectInfo.h>
|
||||
|
||||
#include <QThread>
|
||||
#endif
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
QT_FORWARD_DECLARE_CLASS(ProjectButton)
|
||||
|
||||
class ProjectBuilderWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ProjectBuilderWorker(const ProjectInfo& projectInfo);
|
||||
~ProjectBuilderWorker() = default;
|
||||
|
||||
QString LogFilePath() const;
|
||||
|
||||
public slots:
|
||||
void BuildProject();
|
||||
|
||||
signals:
|
||||
void UpdateProgress(int progress);
|
||||
void Done(QString result);
|
||||
|
||||
private:
|
||||
void WriteErrorLog(const QString& log);
|
||||
|
||||
ProjectInfo m_projectInfo;
|
||||
};
|
||||
|
||||
class ProjectBuilderController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ProjectBuilderController(const ProjectInfo& projectInfo, ProjectButton* projectButton, QWidget* parent = nullptr);
|
||||
~ProjectBuilderController();
|
||||
|
||||
void SetProjectButton(ProjectButton* projectButton);
|
||||
QString GetProjectPath() const;
|
||||
|
||||
public slots:
|
||||
void Start();
|
||||
void UpdateUIProgress(int progress);
|
||||
void HandleResults(const QString& result);
|
||||
|
||||
signals:
|
||||
void Done();
|
||||
|
||||
private:
|
||||
ProjectInfo m_projectInfo;
|
||||
ProjectBuilderWorker* m_worker;
|
||||
QThread m_workerThread;
|
||||
ProjectButton* m_projectButton;
|
||||
QWidget* m_parent;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <QPixmap>
|
||||
#include <QMenu>
|
||||
#include <QSpacerItem>
|
||||
#include <QProgressBar>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
@@ -31,11 +32,26 @@ namespace O3DE::ProjectManager
|
||||
: QLabel(parent)
|
||||
{
|
||||
setObjectName("labelButton");
|
||||
|
||||
QVBoxLayout* vLayout = new QVBoxLayout(this);
|
||||
vLayout->setContentsMargins(0, 0, 0, 0);
|
||||
vLayout->setSpacing(5);
|
||||
|
||||
setLayout(vLayout);
|
||||
m_overlayLabel = new QLabel("", this);
|
||||
m_overlayLabel->setObjectName("labelButtonOverlay");
|
||||
m_overlayLabel->setWordWrap(true);
|
||||
m_overlayLabel->setAlignment(Qt::AlignCenter);
|
||||
m_overlayLabel->setVisible(false);
|
||||
vLayout->addWidget(m_overlayLabel);
|
||||
|
||||
m_buildButton = new QPushButton(tr("Build Project"), this);
|
||||
m_buildButton->setVisible(false);
|
||||
|
||||
m_progressBar = new QProgressBar(this);
|
||||
m_progressBar->setObjectName("labelButtonProgressBar");
|
||||
m_progressBar->setVisible(false);
|
||||
vLayout->addWidget(m_progressBar);
|
||||
}
|
||||
|
||||
void LabelButton::mousePressEvent([[maybe_unused]] QMouseEvent* event)
|
||||
@@ -57,7 +73,22 @@ namespace O3DE::ProjectManager
|
||||
m_overlayLabel->setText(text);
|
||||
}
|
||||
|
||||
ProjectButton::ProjectButton(const ProjectInfo& projectInfo, QWidget* parent)
|
||||
QLabel* LabelButton::GetOverlayLabel()
|
||||
{
|
||||
return m_overlayLabel;
|
||||
}
|
||||
|
||||
QProgressBar* LabelButton::GetProgressBar()
|
||||
{
|
||||
return m_progressBar;
|
||||
}
|
||||
|
||||
QPushButton* LabelButton::GetBuildButton()
|
||||
{
|
||||
return m_buildButton;
|
||||
}
|
||||
|
||||
ProjectButton::ProjectButton(const ProjectInfo& projectInfo, QWidget* parent, bool processing)
|
||||
: QFrame(parent)
|
||||
, m_projectInfo(projectInfo)
|
||||
{
|
||||
@@ -66,10 +97,18 @@ namespace O3DE::ProjectManager
|
||||
m_projectInfo.m_imagePath = ":/DefaultProjectImage.png";
|
||||
}
|
||||
|
||||
Setup();
|
||||
BaseSetup();
|
||||
if (processing)
|
||||
{
|
||||
ProcessingSetup();
|
||||
}
|
||||
else
|
||||
{
|
||||
ReadySetup();
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectButton::Setup()
|
||||
void ProjectButton::BaseSetup()
|
||||
{
|
||||
setObjectName("projectButton");
|
||||
|
||||
@@ -87,8 +126,37 @@ namespace O3DE::ProjectManager
|
||||
m_projectImageLabel->setPixmap(
|
||||
QPixmap(m_projectInfo.m_imagePath).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);
|
||||
hLayout->addWidget(projectNameLabel);
|
||||
}
|
||||
|
||||
vLayout->addWidget(m_projectFooter);
|
||||
}
|
||||
|
||||
void ProjectButton::ProcessingSetup()
|
||||
{
|
||||
m_projectImageLabel->GetOverlayLabel()->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
|
||||
m_projectImageLabel->SetEnabled(false);
|
||||
m_projectImageLabel->SetOverlayText(tr("Processing...\n\n"));
|
||||
|
||||
QProgressBar* progressBar = m_projectImageLabel->GetProgressBar();
|
||||
progressBar->setVisible(true);
|
||||
progressBar->setValue(0);
|
||||
}
|
||||
|
||||
void ProjectButton::ReadySetup()
|
||||
{
|
||||
connect(m_projectImageLabel, &LabelButton::triggered, [this]() { emit OpenProject(m_projectInfo.m_path); });
|
||||
connect(m_projectImageLabel->GetBuildButton(), &QPushButton::clicked, [this](){ emit BuildProject(m_projectInfo); });
|
||||
|
||||
QMenu* menu = new QMenu(this);
|
||||
menu->addAction(tr("Edit Project Settings..."), this, [this]() { emit EditProject(m_projectInfo.m_path); });
|
||||
menu->addAction(tr("Build"), this, [this]() { emit BuildProject(m_projectInfo); });
|
||||
menu->addSeparator();
|
||||
menu->addAction(tr("Open Project folder..."), this, [this]()
|
||||
{
|
||||
@@ -100,30 +168,33 @@ namespace O3DE::ProjectManager
|
||||
menu->addAction(tr("Remove from O3DE"), this, [this]() { emit RemoveProject(m_projectInfo.m_path); });
|
||||
menu->addAction(tr("Delete this Project"), this, [this]() { emit DeleteProject(m_projectInfo.m_path); });
|
||||
|
||||
QFrame* footer = new QFrame(this);
|
||||
QHBoxLayout* hLayout = new QHBoxLayout();
|
||||
hLayout->setContentsMargins(0, 0, 0, 0);
|
||||
footer->setLayout(hLayout);
|
||||
{
|
||||
QLabel* projectNameLabel = new QLabel(m_projectInfo.m_displayName, this);
|
||||
hLayout->addWidget(projectNameLabel);
|
||||
|
||||
QPushButton* projectMenuButton = new QPushButton(this);
|
||||
projectMenuButton->setObjectName("projectMenuButton");
|
||||
projectMenuButton->setMenu(menu);
|
||||
hLayout->addWidget(projectMenuButton);
|
||||
}
|
||||
|
||||
vLayout->addWidget(footer);
|
||||
QPushButton* projectMenuButton = new QPushButton(this);
|
||||
projectMenuButton->setObjectName("projectMenuButton");
|
||||
projectMenuButton->setMenu(menu);
|
||||
m_projectFooter->layout()->addWidget(projectMenuButton);
|
||||
}
|
||||
|
||||
void ProjectButton::SetButtonEnabled(bool enabled)
|
||||
void ProjectButton::SetLaunchButtonEnabled(bool enabled)
|
||||
{
|
||||
m_projectImageLabel->SetEnabled(enabled);
|
||||
}
|
||||
|
||||
void ProjectButton::ShowBuildButton(bool show)
|
||||
{
|
||||
QSpacerItem* buttonSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
|
||||
m_projectImageLabel->layout()->addItem(buttonSpacer);
|
||||
m_projectImageLabel->layout()->addWidget(m_projectImageLabel->GetBuildButton());
|
||||
m_projectImageLabel->GetBuildButton()->setVisible(show);
|
||||
}
|
||||
|
||||
void ProjectButton::SetButtonOverlayText(const QString& text)
|
||||
{
|
||||
m_projectImageLabel->SetOverlayText(text);
|
||||
}
|
||||
|
||||
void ProjectButton::SetProgressBarValue(int progress)
|
||||
{
|
||||
m_projectImageLabel->GetProgressBar()->setValue(progress);
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
QT_FORWARD_DECLARE_CLASS(QPixmap)
|
||||
QT_FORWARD_DECLARE_CLASS(QPushButton)
|
||||
QT_FORWARD_DECLARE_CLASS(QAction)
|
||||
QT_FORWARD_DECLARE_CLASS(QProgressBar)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
@@ -36,6 +37,10 @@ namespace O3DE::ProjectManager
|
||||
void SetEnabled(bool enabled);
|
||||
void SetOverlayText(const QString& text);
|
||||
|
||||
QLabel* GetOverlayLabel();
|
||||
QProgressBar* GetProgressBar();
|
||||
QPushButton* GetBuildButton();
|
||||
|
||||
signals:
|
||||
void triggered();
|
||||
|
||||
@@ -44,6 +49,8 @@ namespace O3DE::ProjectManager
|
||||
|
||||
private:
|
||||
QLabel* m_overlayLabel;
|
||||
QProgressBar* m_progressBar;
|
||||
QPushButton* m_buildButton;
|
||||
bool m_enabled = true;
|
||||
};
|
||||
|
||||
@@ -53,11 +60,13 @@ namespace O3DE::ProjectManager
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
explicit ProjectButton(const ProjectInfo& m_projectInfo, QWidget* parent = nullptr);
|
||||
explicit ProjectButton(const ProjectInfo& m_projectInfo, QWidget* parent = nullptr, bool processing = false);
|
||||
~ProjectButton() = default;
|
||||
|
||||
void SetButtonEnabled(bool enabled);
|
||||
void SetLaunchButtonEnabled(bool enabled);
|
||||
void ShowBuildButton(bool show);
|
||||
void SetButtonOverlayText(const QString& text);
|
||||
void SetProgressBarValue(int progress);
|
||||
|
||||
signals:
|
||||
void OpenProject(const QString& projectName);
|
||||
@@ -65,11 +74,15 @@ namespace O3DE::ProjectManager
|
||||
void CopyProject(const QString& projectName);
|
||||
void RemoveProject(const QString& projectName);
|
||||
void DeleteProject(const QString& projectName);
|
||||
void BuildProject(const ProjectInfo& projectInfo);
|
||||
|
||||
private:
|
||||
void Setup();
|
||||
void BaseSetup();
|
||||
void ProcessingSetup();
|
||||
void ReadySetup();
|
||||
|
||||
ProjectInfo m_projectInfo;
|
||||
LabelButton* m_projectImageLabel;
|
||||
QFrame* m_projectFooter;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
ProjectInfo::ProjectInfo(const QString& path, const QString& projectName, const QString& displayName,
|
||||
const QString& imagePath, const QString& backgroundImagePath, bool isNew)
|
||||
const QString& imagePath, const QString& backgroundImagePath, bool needsBuild)
|
||||
: m_path(path)
|
||||
, m_projectName(projectName)
|
||||
, m_displayName(displayName)
|
||||
, m_imagePath(imagePath)
|
||||
, m_backgroundImagePath(backgroundImagePath)
|
||||
, m_isNew(isNew)
|
||||
, m_needsBuild(needsBuild)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace O3DE::ProjectManager
|
||||
public:
|
||||
ProjectInfo() = default;
|
||||
ProjectInfo(const QString& path, const QString& projectName, const QString& displayName,
|
||||
const QString& imagePath, const QString& backgroundImagePath, bool isNew);
|
||||
const QString& imagePath, const QString& backgroundImagePath, bool needsBuild);
|
||||
bool operator==(const ProjectInfo& rhs);
|
||||
bool operator!=(const ProjectInfo& rhs);
|
||||
|
||||
@@ -42,6 +42,6 @@ namespace O3DE::ProjectManager
|
||||
QString m_backgroundImagePath;
|
||||
|
||||
// Used in project creation
|
||||
bool m_isNew = false; //! Is this a new project or existing
|
||||
bool m_needsBuild = false; //! Does this project need to be built
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
#include <QFileDialog>
|
||||
#include <QDir>
|
||||
#include <QMessageBox>
|
||||
#include <QProgressDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
#include <QProcessEnvironment>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
@@ -192,6 +194,49 @@ namespace O3DE::ProjectManager
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool IsVS2019Installed_internal()
|
||||
{
|
||||
QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
|
||||
QString programFilesPath = environment.value("ProgramFiles(x86)");
|
||||
QString vsWherePath = programFilesPath + "\\Microsoft Visual Studio\\Installer\\vswhere.exe";
|
||||
|
||||
QFileInfo vsWhereFile(vsWherePath);
|
||||
if (vsWhereFile.exists() && vsWhereFile.isFile())
|
||||
{
|
||||
QProcess vsWhereProcess;
|
||||
vsWhereProcess.setProcessChannelMode(QProcess::MergedChannels);
|
||||
|
||||
vsWhereProcess.start(
|
||||
vsWherePath,
|
||||
QStringList{ "-version", "16.0", "-latest", "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
|
||||
"-property", "isComplete" });
|
||||
|
||||
if (!vsWhereProcess.waitForStarted())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while (vsWhereProcess.waitForReadyRead())
|
||||
{
|
||||
}
|
||||
|
||||
QString vsWhereOutput(vsWhereProcess.readAllStandardOutput());
|
||||
if (vsWhereOutput.startsWith("1"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsVS2019Installed()
|
||||
{
|
||||
static bool vs2019Installed = IsVS2019Installed_internal();
|
||||
|
||||
return vs2019Installed;
|
||||
}
|
||||
|
||||
ProjectManagerScreen GetProjectManagerScreen(const QString& screen)
|
||||
{
|
||||
auto iter = s_ProjectManagerStringNames.find(screen);
|
||||
@@ -202,6 +247,5 @@ namespace O3DE::ProjectManager
|
||||
|
||||
return ProjectManagerScreen::Invalid;
|
||||
}
|
||||
|
||||
} // namespace ProjectUtils
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -25,6 +25,9 @@ namespace O3DE::ProjectManager
|
||||
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 IsVS2019Installed();
|
||||
|
||||
ProjectManagerScreen GetProjectManagerScreen(const QString& screen);
|
||||
} // namespace ProjectUtils
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include <ProjectButtonWidget.h>
|
||||
#include <PythonBindingsInterface.h>
|
||||
#include <ProjectUtils.h>
|
||||
#include <ProjectBuilder.h>
|
||||
#include <ScreensCtrl.h>
|
||||
|
||||
#include <AzQtComponents/Components/FlowLayout.h>
|
||||
#include <AzCore/Platform.h>
|
||||
@@ -42,6 +44,8 @@
|
||||
#include <QSettings>
|
||||
#include <QMessageBox>
|
||||
#include <QTimer>
|
||||
#include <QQueue>
|
||||
#include <QDir>
|
||||
|
||||
//#define DISPLAY_PROJECT_DEV_DATA true
|
||||
|
||||
@@ -66,6 +70,14 @@ namespace O3DE::ProjectManager
|
||||
m_stack->addWidget(m_projectsContent);
|
||||
|
||||
vLayout->addWidget(m_stack);
|
||||
|
||||
connect(reinterpret_cast<ScreensCtrl*>(parent), &ScreensCtrl::NotifyBuildProject, this, &ProjectsScreen::SuggestBuildProject);
|
||||
}
|
||||
|
||||
ProjectsScreen::~ProjectsScreen()
|
||||
|
||||
{
|
||||
delete m_currentBuilder;
|
||||
}
|
||||
|
||||
QFrame* ProjectsScreen::CreateFirstTimeContent()
|
||||
@@ -110,7 +122,7 @@ namespace O3DE::ProjectManager
|
||||
return frame;
|
||||
}
|
||||
|
||||
QFrame* ProjectsScreen::CreateProjectsContent()
|
||||
QFrame* ProjectsScreen::CreateProjectsContent(QString buildProjectPath, ProjectButton** projectButton)
|
||||
{
|
||||
QFrame* frame = new QFrame(this);
|
||||
frame->setObjectName("projectsContent");
|
||||
@@ -158,30 +170,43 @@ namespace O3DE::ProjectManager
|
||||
projectsScrollArea->setWidgetResizable(true);
|
||||
|
||||
#ifndef DISPLAY_PROJECT_DEV_DATA
|
||||
// Iterate once to insert building project first
|
||||
if (!buildProjectPath.isEmpty())
|
||||
{
|
||||
buildProjectPath = QDir::fromNativeSeparators(buildProjectPath);
|
||||
for (auto project : projectsResult.GetValue())
|
||||
{
|
||||
if (QDir::fromNativeSeparators(project.m_path) == buildProjectPath)
|
||||
{
|
||||
ProjectButton* buildingProjectButton = CreateProjectButton(project, flowLayout, true);
|
||||
|
||||
if (projectButton)
|
||||
{
|
||||
*projectButton = buildingProjectButton;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto project : projectsResult.GetValue())
|
||||
#else
|
||||
ProjectInfo project = projectsResult.GetValue().at(0);
|
||||
for (int i = 0; i < 15; i++)
|
||||
#endif
|
||||
{
|
||||
ProjectButton* projectButton;
|
||||
|
||||
QString projectPreviewPath = project.m_path + m_projectPreviewImagePath;
|
||||
QFileInfo doesPreviewExist(projectPreviewPath);
|
||||
if (doesPreviewExist.exists() && doesPreviewExist.isFile())
|
||||
// Add all other projects skipping building project
|
||||
// Safe if no building project because it is just an empty string
|
||||
if (project.m_path != buildProjectPath)
|
||||
{
|
||||
project.m_imagePath = projectPreviewPath;
|
||||
ProjectButton* projectButtonWidget = CreateProjectButton(project, flowLayout);
|
||||
|
||||
if (RequiresBuildProjectIterator(project.m_path) != m_requiresBuild.end())
|
||||
{
|
||||
projectButtonWidget->ShowBuildButton(true);
|
||||
}
|
||||
}
|
||||
|
||||
projectButton = new ProjectButton(project, this);
|
||||
|
||||
flowLayout->addWidget(projectButton);
|
||||
|
||||
connect(projectButton, &ProjectButton::OpenProject, this, &ProjectsScreen::HandleOpenProject);
|
||||
connect(projectButton, &ProjectButton::EditProject, this, &ProjectsScreen::HandleEditProject);
|
||||
connect(projectButton, &ProjectButton::CopyProject, this, &ProjectsScreen::HandleCopyProject);
|
||||
connect(projectButton, &ProjectButton::RemoveProject, this, &ProjectsScreen::HandleRemoveProject);
|
||||
connect(projectButton, &ProjectButton::DeleteProject, this, &ProjectsScreen::HandleDeleteProject);
|
||||
}
|
||||
|
||||
layout->addWidget(projectsScrollArea);
|
||||
@@ -191,6 +216,60 @@ namespace O3DE::ProjectManager
|
||||
return frame;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
flowLayout->addWidget(projectButton);
|
||||
|
||||
if (!processing)
|
||||
{
|
||||
connect(projectButton, &ProjectButton::OpenProject, this, &ProjectsScreen::HandleOpenProject);
|
||||
connect(projectButton, &ProjectButton::EditProject, this, &ProjectsScreen::HandleEditProject);
|
||||
connect(projectButton, &ProjectButton::CopyProject, this, &ProjectsScreen::HandleCopyProject);
|
||||
connect(projectButton, &ProjectButton::RemoveProject, this, &ProjectsScreen::HandleRemoveProject);
|
||||
connect(projectButton, &ProjectButton::DeleteProject, this, &ProjectsScreen::HandleDeleteProject);
|
||||
}
|
||||
connect(projectButton, &ProjectButton::BuildProject, this, &ProjectsScreen::QueueBuildProject);
|
||||
|
||||
return projectButton;
|
||||
}
|
||||
|
||||
void ProjectsScreen::ResetProjectsContent()
|
||||
{
|
||||
// refresh the projects content by re-creating it for now
|
||||
if (m_projectsContent)
|
||||
{
|
||||
m_stack->removeWidget(m_projectsContent);
|
||||
m_projectsContent->deleteLater();
|
||||
}
|
||||
|
||||
// Make sure to update builder with latest Project Button
|
||||
if (m_currentBuilder)
|
||||
{
|
||||
ProjectButton* projectButtonPtr;
|
||||
|
||||
m_projectsContent = CreateProjectsContent(m_currentBuilder->GetProjectPath(), &projectButtonPtr);
|
||||
m_currentBuilder->SetProjectButton(projectButtonPtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_projectsContent = CreateProjectsContent();
|
||||
}
|
||||
|
||||
m_stack->addWidget(m_projectsContent);
|
||||
m_stack->setCurrentWidget(m_projectsContent);
|
||||
}
|
||||
|
||||
ProjectManagerScreen ProjectsScreen::GetScreenEnum()
|
||||
{
|
||||
return ProjectManagerScreen::Projects;
|
||||
@@ -237,7 +316,7 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
if (ProjectUtils::AddProjectDialog(this))
|
||||
{
|
||||
emit ResetScreenRequest(ProjectManagerScreen::Projects);
|
||||
ResetProjectsContent();
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::Projects);
|
||||
}
|
||||
}
|
||||
@@ -245,38 +324,47 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
if (!projectPath.isEmpty())
|
||||
{
|
||||
AZ::IO::FixedMaxPath executableDirectory = AZ::Utils::GetExecutableDirectory();
|
||||
AZStd::string executableFilename = "Editor";
|
||||
AZ::IO::FixedMaxPath editorExecutablePath = executableDirectory / (executableFilename + AZ_TRAIT_OS_EXECUTABLE_EXTENSION);
|
||||
auto cmdPath = AZ::IO::FixedMaxPathString::format("%s -regset=\"/Amazon/AzCore/Bootstrap/project_path=%s\"", editorExecutablePath.c_str(), projectPath.toStdString().c_str());
|
||||
if (!WarnIfInBuildQueue(projectPath))
|
||||
{
|
||||
AZ::IO::FixedMaxPath executableDirectory = AZ::Utils::GetExecutableDirectory();
|
||||
AZStd::string executableFilename = "Editor";
|
||||
AZ::IO::FixedMaxPath editorExecutablePath = executableDirectory / (executableFilename + AZ_TRAIT_OS_EXECUTABLE_EXTENSION);
|
||||
auto cmdPath = AZ::IO::FixedMaxPathString::format(
|
||||
"%s -regset=\"/Amazon/AzCore/Bootstrap/project_path=%s\"", editorExecutablePath.c_str(),
|
||||
projectPath.toStdString().c_str());
|
||||
|
||||
AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
|
||||
processLaunchInfo.m_commandlineParameters = cmdPath;
|
||||
bool launchSucceeded = AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo);
|
||||
if (!launchSucceeded)
|
||||
{
|
||||
AZ_Error("ProjectManager", false, "Failed to launch editor");
|
||||
QMessageBox::critical( this, tr("Error"), tr("Failed to launch the Editor, please verify the project settings are valid."));
|
||||
}
|
||||
else
|
||||
{
|
||||
// prevent the user from accidentally pressing the button while the editor is launching
|
||||
// and let them know what's happening
|
||||
ProjectButton* button = qobject_cast<ProjectButton*>(sender());
|
||||
if (button)
|
||||
AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
|
||||
processLaunchInfo.m_commandlineParameters = cmdPath;
|
||||
bool launchSucceeded = AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo);
|
||||
if (!launchSucceeded)
|
||||
{
|
||||
button->SetButtonEnabled(false);
|
||||
button->SetButtonOverlayText(tr("Opening Editor..."));
|
||||
AZ_Error("ProjectManager", false, "Failed to launch editor");
|
||||
QMessageBox::critical(
|
||||
this, tr("Error"), tr("Failed to launch the Editor, please verify the project settings are valid."));
|
||||
}
|
||||
else
|
||||
{
|
||||
// prevent the user from accidentally pressing the button while the editor is launching
|
||||
// and let them know what's happening
|
||||
ProjectButton* button = qobject_cast<ProjectButton*>(sender());
|
||||
if (button)
|
||||
{
|
||||
button->SetLaunchButtonEnabled(false);
|
||||
button->SetButtonOverlayText(tr("Opening Editor..."));
|
||||
}
|
||||
|
||||
// enable the button after 3 seconds
|
||||
constexpr int waitTimeInMs = 3000;
|
||||
QTimer::singleShot(waitTimeInMs, this, [this, button] {
|
||||
if (button)
|
||||
// enable the button after 3 seconds
|
||||
constexpr int waitTimeInMs = 3000;
|
||||
QTimer::singleShot(
|
||||
waitTimeInMs, this,
|
||||
[this, button]
|
||||
{
|
||||
button->SetButtonEnabled(true);
|
||||
}
|
||||
});
|
||||
if (button)
|
||||
{
|
||||
button->SetLaunchButtonEnabled(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -288,38 +376,90 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
void ProjectsScreen::HandleEditProject(const QString& projectPath)
|
||||
{
|
||||
emit NotifyCurrentProject(projectPath);
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::UpdateProject);
|
||||
if (!WarnIfInBuildQueue(projectPath))
|
||||
{
|
||||
emit NotifyCurrentProject(projectPath);
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::UpdateProject);
|
||||
}
|
||||
}
|
||||
void ProjectsScreen::HandleCopyProject(const QString& projectPath)
|
||||
{
|
||||
// Open file dialog and choose location for copied project then register copy with O3DE
|
||||
if (ProjectUtils::CopyProjectDialog(projectPath, this))
|
||||
if (!WarnIfInBuildQueue(projectPath))
|
||||
{
|
||||
emit ResetScreenRequest(ProjectManagerScreen::Projects);
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::Projects);
|
||||
// Open file dialog and choose location for copied project then register copy with O3DE
|
||||
if (ProjectUtils::CopyProjectDialog(projectPath, this))
|
||||
{
|
||||
ResetProjectsContent();
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::Projects);
|
||||
}
|
||||
}
|
||||
}
|
||||
void ProjectsScreen::HandleRemoveProject(const QString& projectPath)
|
||||
{
|
||||
// Unregister Project from O3DE and reload projects
|
||||
if (ProjectUtils::UnregisterProject(projectPath))
|
||||
if (!WarnIfInBuildQueue(projectPath))
|
||||
{
|
||||
emit ResetScreenRequest(ProjectManagerScreen::Projects);
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::Projects);
|
||||
// Unregister Project from O3DE and reload projects
|
||||
if (ProjectUtils::UnregisterProject(projectPath))
|
||||
{
|
||||
ResetProjectsContent();
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::Projects);
|
||||
}
|
||||
}
|
||||
}
|
||||
void ProjectsScreen::HandleDeleteProject(const QString& projectPath)
|
||||
{
|
||||
QMessageBox::StandardButton warningResult = QMessageBox::warning(
|
||||
this, tr("Delete Project"), tr("Are you sure?\nProject will be removed from O3DE and directory will be deleted!"),
|
||||
QMessageBox::No | QMessageBox::Yes);
|
||||
|
||||
if (warningResult == QMessageBox::Yes)
|
||||
if (!WarnIfInBuildQueue(projectPath))
|
||||
{
|
||||
// Remove project from O3DE and delete from disk
|
||||
HandleRemoveProject(projectPath);
|
||||
ProjectUtils::DeleteProjectFiles(projectPath);
|
||||
QMessageBox::StandardButton warningResult = QMessageBox::warning(this,
|
||||
tr("Delete Project"),
|
||||
tr("Are you sure?\nProject will be unregistered from O3DE and project directory will be deleted from your disk."),
|
||||
QMessageBox::No | QMessageBox::Yes);
|
||||
|
||||
if (warningResult == QMessageBox::Yes)
|
||||
{
|
||||
// Remove project from O3DE and delete from disk
|
||||
HandleRemoveProject(projectPath);
|
||||
ProjectUtils::DeleteProjectFiles(projectPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectsScreen::SuggestBuildProject(const ProjectInfo& projectInfo)
|
||||
{
|
||||
if (projectInfo.m_needsBuild)
|
||||
{
|
||||
if (RequiresBuildProjectIterator(projectInfo.m_path) == m_requiresBuild.end())
|
||||
{
|
||||
m_requiresBuild.append(projectInfo);
|
||||
}
|
||||
ResetProjectsContent();
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::information(this,
|
||||
tr("Project Should be rebuilt."),
|
||||
projectInfo.m_projectName + tr(" project likely needs to be rebuilt."));
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectsScreen::QueueBuildProject(const ProjectInfo& projectInfo)
|
||||
{
|
||||
auto requiredIter = RequiresBuildProjectIterator(projectInfo.m_path);
|
||||
if (requiredIter != m_requiresBuild.end())
|
||||
{
|
||||
m_requiresBuild.erase(requiredIter);
|
||||
}
|
||||
|
||||
if (!BuildQueueContainsProject(projectInfo.m_path))
|
||||
{
|
||||
if (m_buildQueue.empty() && !m_currentBuilder)
|
||||
{
|
||||
StartProjectBuild(projectInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_buildQueue.append(projectInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,17 +471,7 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
else
|
||||
{
|
||||
// refresh the projects content by re-creating it for now
|
||||
if (m_projectsContent)
|
||||
{
|
||||
m_stack->removeWidget(m_projectsContent);
|
||||
m_projectsContent->deleteLater();
|
||||
}
|
||||
|
||||
m_projectsContent = CreateProjectsContent();
|
||||
|
||||
m_stack->addWidget(m_projectsContent);
|
||||
m_stack->setCurrentWidget(m_projectsContent);
|
||||
ResetProjectsContent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -363,4 +493,89 @@ namespace O3DE::ProjectManager
|
||||
return displayFirstTimeContent;
|
||||
}
|
||||
|
||||
void ProjectsScreen::StartProjectBuild(const ProjectInfo& projectInfo)
|
||||
{
|
||||
if (ProjectUtils::IsVS2019Installed())
|
||||
{
|
||||
QMessageBox::StandardButton buildProject = QMessageBox::information(
|
||||
this,
|
||||
tr("Building \"%1\"").arg(projectInfo.m_projectName),
|
||||
tr("Ready to build \"%1\"?").arg(projectInfo.m_projectName),
|
||||
QMessageBox::No | QMessageBox::Yes);
|
||||
|
||||
if (buildProject == QMessageBox::Yes)
|
||||
{
|
||||
m_currentBuilder = new ProjectBuilderController(projectInfo, nullptr, this);
|
||||
ResetProjectsContent();
|
||||
connect(m_currentBuilder, &ProjectBuilderController::Done, this, &ProjectsScreen::ProjectBuildDone);
|
||||
|
||||
m_currentBuilder->Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
ProjectBuildDone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectsScreen::ProjectBuildDone()
|
||||
{
|
||||
delete m_currentBuilder;
|
||||
m_currentBuilder = nullptr;
|
||||
|
||||
if (!m_buildQueue.empty())
|
||||
{
|
||||
StartProjectBuild(m_buildQueue.front());
|
||||
m_buildQueue.pop_front();
|
||||
}
|
||||
else
|
||||
{
|
||||
ResetProjectsContent();
|
||||
}
|
||||
}
|
||||
|
||||
QList<ProjectInfo>::iterator ProjectsScreen::RequiresBuildProjectIterator(const QString& projectPath)
|
||||
{
|
||||
QString nativeProjPath(QDir::toNativeSeparators(projectPath));
|
||||
auto projectIter = m_requiresBuild.begin();
|
||||
for (; projectIter != m_requiresBuild.end(); ++projectIter)
|
||||
{
|
||||
if (QDir::toNativeSeparators(projectIter->m_path) == nativeProjPath)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return projectIter;
|
||||
}
|
||||
|
||||
bool ProjectsScreen::BuildQueueContainsProject(const QString& projectPath)
|
||||
{
|
||||
QString nativeProjPath(QDir::toNativeSeparators(projectPath));
|
||||
for (const ProjectInfo& project : m_buildQueue)
|
||||
{
|
||||
if (QDir::toNativeSeparators(project.m_path) == nativeProjPath)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ProjectsScreen::WarnIfInBuildQueue(const QString& projectPath)
|
||||
{
|
||||
if (BuildQueueContainsProject(projectPath))
|
||||
{
|
||||
QMessageBox::warning(
|
||||
this,
|
||||
tr("Action Temporarily Disabled!"),
|
||||
tr("Action not allowed on projects in build queue."));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -13,21 +13,28 @@
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <ScreenWidget.h>
|
||||
#include <ProjectInfo.h>
|
||||
|
||||
#include <QQueue>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QPaintEvent)
|
||||
QT_FORWARD_DECLARE_CLASS(QFrame)
|
||||
QT_FORWARD_DECLARE_CLASS(QStackedWidget)
|
||||
QT_FORWARD_DECLARE_CLASS(QLayout)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
QT_FORWARD_DECLARE_CLASS(ProjectBuilderController);
|
||||
QT_FORWARD_DECLARE_CLASS(ProjectButton);
|
||||
|
||||
class ProjectsScreen
|
||||
: public ScreenWidget
|
||||
{
|
||||
|
||||
public:
|
||||
explicit ProjectsScreen(QWidget* parent = nullptr);
|
||||
~ProjectsScreen() = default;
|
||||
~ProjectsScreen();
|
||||
|
||||
ProjectManagerScreen GetScreenEnum() override;
|
||||
QString GetTabText() override;
|
||||
@@ -35,6 +42,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
protected:
|
||||
void NotifyCurrentScreen() override;
|
||||
void ProjectBuildDone();
|
||||
|
||||
protected slots:
|
||||
void HandleNewProjectButton();
|
||||
@@ -45,19 +53,32 @@ namespace O3DE::ProjectManager
|
||||
void HandleRemoveProject(const QString& projectPath);
|
||||
void HandleDeleteProject(const QString& projectPath);
|
||||
|
||||
void SuggestBuildProject(const ProjectInfo& projectInfo);
|
||||
void QueueBuildProject(const ProjectInfo& projectInfo);
|
||||
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
|
||||
private:
|
||||
QFrame* CreateFirstTimeContent();
|
||||
QFrame* CreateProjectsContent();
|
||||
QFrame* CreateProjectsContent(QString buildProjectPath = "", ProjectButton** projectButton = nullptr);
|
||||
ProjectButton* CreateProjectButton(ProjectInfo& project, QLayout* flowLayout, bool processing = false);
|
||||
void ResetProjectsContent();
|
||||
bool ShouldDisplayFirstTimeContent();
|
||||
|
||||
QAction* m_createNewProjectAction;
|
||||
QAction* m_addExistingProjectAction;
|
||||
void StartProjectBuild(const ProjectInfo& projectInfo);
|
||||
QList<ProjectInfo>::iterator RequiresBuildProjectIterator(const QString& projectPath);
|
||||
bool BuildQueueContainsProject(const QString& projectPath);
|
||||
bool WarnIfInBuildQueue(const QString& projectPath);
|
||||
|
||||
QAction* m_createNewProjectAction = nullptr;
|
||||
QAction* m_addExistingProjectAction = nullptr;
|
||||
QPixmap m_background;
|
||||
QFrame* m_firstTimeContent;
|
||||
QFrame* m_projectsContent;
|
||||
QStackedWidget* m_stack;
|
||||
QFrame* m_firstTimeContent = nullptr;
|
||||
QFrame* m_projectsContent = nullptr;
|
||||
QStackedWidget* m_stack = nullptr;
|
||||
QList<ProjectInfo> m_requiresBuild;
|
||||
QQueue<ProjectInfo> m_buildQueue;
|
||||
ProjectBuilderController* m_currentBuilder = nullptr;
|
||||
|
||||
const QString m_projectPreviewImagePath = "/preview.png";
|
||||
|
||||
|
||||
@@ -667,7 +667,7 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
ProjectInfo projectInfo;
|
||||
projectInfo.m_path = Py_To_String(path);
|
||||
projectInfo.m_isNew = false;
|
||||
projectInfo.m_needsBuild = false;
|
||||
|
||||
auto projectData = m_manifest.attr("get_project_json_data")(pybind11::none(), path);
|
||||
if (pybind11::isinstance<pybind11::dict>(projectData))
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <ScreenDefs.h>
|
||||
#include <ProjectInfo.h>
|
||||
|
||||
#include <QWidget>
|
||||
#include <QStyleOption>
|
||||
@@ -61,6 +62,7 @@ namespace O3DE::ProjectManager
|
||||
void GotoPreviousScreenRequest();
|
||||
void ResetScreenRequest(ProjectManagerScreen screen);
|
||||
void NotifyCurrentProject(const QString& projectPath);
|
||||
void NotifyBuildProject(const ProjectInfo& projectInfo);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -177,6 +177,7 @@ namespace O3DE::ProjectManager
|
||||
connect(newScreen, &ScreenWidget::GotoPreviousScreenRequest, this, &ScreensCtrl::GotoPreviousScreen);
|
||||
connect(newScreen, &ScreenWidget::ResetScreenRequest, this, &ScreensCtrl::ResetScreen);
|
||||
connect(newScreen, &ScreenWidget::NotifyCurrentProject, this, &ScreensCtrl::NotifyCurrentProject);
|
||||
connect(newScreen, &ScreenWidget::NotifyBuildProject, this, &ScreensCtrl::NotifyBuildProject);
|
||||
}
|
||||
|
||||
void ScreensCtrl::ResetAllScreens()
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <ScreenDefs.h>
|
||||
#include <ProjectInfo.h>
|
||||
|
||||
#include <QStackedWidget>
|
||||
#include <QStack>
|
||||
@@ -39,6 +40,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
signals:
|
||||
void NotifyCurrentProject(const QString& projectPath);
|
||||
void NotifyBuildProject(const ProjectInfo& projectInfo);
|
||||
|
||||
public slots:
|
||||
bool ChangeToScreen(ProjectManagerScreen screen);
|
||||
|
||||
@@ -119,7 +119,9 @@ namespace O3DE::ProjectManager
|
||||
|
||||
void UpdateProjectCtrl::HandleNextButton()
|
||||
{
|
||||
if (m_stack->currentIndex() == ScreenOrder::Settings)
|
||||
bool shouldRebuild = false;
|
||||
|
||||
if (m_stack->currentIndex() == ScreenOrder::Settings && m_updateSettingsScreen)
|
||||
{
|
||||
if (m_updateSettingsScreen)
|
||||
{
|
||||
@@ -155,11 +157,17 @@ namespace O3DE::ProjectManager
|
||||
m_projectInfo = newProjectSettings;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_stack->currentIndex() == ScreenOrder::Gems && m_gemCatalogScreen)
|
||||
else if (m_stack->currentIndex() == ScreenOrder::Gems && m_gemCatalogScreen)
|
||||
{
|
||||
// Enable or disable the gems that got adjusted in the gem catalog and apply them to the given project.
|
||||
m_gemCatalogScreen->EnableDisableGemsForProject(m_projectInfo.m_path);
|
||||
|
||||
shouldRebuild = true;
|
||||
}
|
||||
|
||||
if (shouldRebuild)
|
||||
{
|
||||
emit NotifyBuildProject(m_projectInfo);
|
||||
}
|
||||
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::Projects);
|
||||
|
||||
Reference in New Issue
Block a user