Open CMake GUI from Project Manager (#4360)

This provides a fast way for engineers who want to configure -> generate -> open project in IDE -> build & run to do so without waiting for a potentially lengthy Project Manager build.

Signed-off-by: AMZN-alexpete <26804013+AMZN-alexpete@users.noreply.github.com>
monroegm-disable-blank-issue-2
Alex Peterson 4 years ago committed by GitHub
parent c9608846a1
commit 555e95679d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -8,6 +8,7 @@
#include <ProjectUtils.h> #include <ProjectUtils.h>
#include <ProjectManagerDefs.h> #include <ProjectManagerDefs.h>
#include <QProcessEnvironment> #include <QProcessEnvironment>
#include <QDir>
namespace O3DE::ProjectManager namespace O3DE::ProjectManager
{ {
@ -18,7 +19,10 @@ namespace O3DE::ProjectManager
AZ::Outcome<QProcessEnvironment, QString> GetCommandLineProcessEnvironment() AZ::Outcome<QProcessEnvironment, QString> GetCommandLineProcessEnvironment()
{ {
return AZ::Success(QProcessEnvironment(QProcessEnvironment::systemEnvironment())); QProcessEnvironment currentEnvironment(QProcessEnvironment::systemEnvironment());
currentEnvironment.insert("CC", "clang-12");
currentEnvironment.insert("CXX", "clang++-12");
return AZ::Success(currentEnvironment);
} }
AZ::Outcome<QString, QString> FindSupportedCompilerForPlatform() AZ::Outcome<QString, QString> FindSupportedCompilerForPlatform()
@ -27,7 +31,7 @@ namespace O3DE::ProjectManager
auto whichCMakeResult = ProjectUtils::ExecuteCommandResult("which", QStringList{ProjectCMakeCommand}, QProcessEnvironment::systemEnvironment()); auto whichCMakeResult = ProjectUtils::ExecuteCommandResult("which", QStringList{ProjectCMakeCommand}, QProcessEnvironment::systemEnvironment());
if (!whichCMakeResult.IsSuccess()) if (!whichCMakeResult.IsSuccess())
{ {
return AZ::Failure(QObject::tr("CMake not found. \n\n" return AZ::Failure(QObject::tr("CMake not found. <br><br>"
"Make sure that the minimum version of CMake is installed and available from the command prompt. " "Make sure that the minimum version of CMake is installed and available from the command prompt. "
"Refer to the <a href='https://o3de.org/docs/welcome-guide/setup/requirements/#cmake'>O3DE requirements</a> page for more information.")); "Refer to the <a href='https://o3de.org/docs/welcome-guide/setup/requirements/#cmake'>O3DE requirements</a> page for more information."));
} }
@ -45,10 +49,42 @@ namespace O3DE::ProjectManager
return AZ::Success(supportClangCommand); return AZ::Success(supportClangCommand);
} }
} }
return AZ::Failure(QObject::tr("Clang not found. \n\n" return AZ::Failure(QObject::tr("Clang not found. <br><br>"
"Make sure that the clang is installed and available from the command prompt. " "Make sure that the clang is installed and available from the command prompt. "
"Refer to the <a href='https://o3de.org/docs/welcome-guide/setup/requirements/#cmake'>O3DE requirements</a> page for more information.")); "Refer to the <a href='https://o3de.org/docs/welcome-guide/setup/requirements/#cmake'>O3DE requirements</a> page for more information."));
} }
AZ::Outcome<void, QString> OpenCMakeGUI(const QString& projectPath)
{
AZ::Outcome processEnvResult = GetCommandLineProcessEnvironment();
if (!processEnvResult.IsSuccess())
{
return AZ::Failure(processEnvResult.GetError());
}
QString projectBuildPath = QDir(projectPath).filePath(ProjectBuildPathPostfix);
AZ::Outcome projectBuildPathResult = GetProjectBuildPath(projectPath);
if (projectBuildPathResult.IsSuccess())
{
projectBuildPath = projectBuildPathResult.GetValue();
}
QProcess process;
process.setProcessEnvironment(processEnvResult.GetValue());
// if the project build path is relative, it should be relative to the project path
process.setWorkingDirectory(projectPath);
process.setProgram("cmake-gui");
process.setArguments({ "-S", projectPath, "-B", projectBuildPath });
if(!process.startDetached())
{
return AZ::Failure(QObject::tr("Failed to start CMake GUI"));
}
return AZ::Success();
}
} // namespace ProjectUtils } // namespace ProjectUtils
} // namespace O3DE::ProjectManager } // namespace O3DE::ProjectManager

@ -8,6 +8,7 @@
#include <ProjectUtils.h> #include <ProjectUtils.h>
#include <QProcess> #include <QProcess>
#include <QStandardPaths>
namespace O3DE::ProjectManager namespace O3DE::ProjectManager
{ {
@ -61,5 +62,37 @@ namespace O3DE::ProjectManager
return AZ::Success(xcodeBuilderVersionNumber); return AZ::Success(xcodeBuilderVersionNumber);
} }
AZ::Outcome<void, QString> OpenCMakeGUI(const QString& projectPath)
{
const QString cmakeHelp = QObject::tr("Please verify you've installed CMake.app from "
"<a href=\"https://cmake.org\">cmake.org</a> or, if using HomeBrew, "
"have installed it with <pre>brew install --cask cmake</pre>");
QString cmakeAppPath = QStandardPaths::locate(QStandardPaths::ApplicationsLocation, "CMake.app", QStandardPaths::LocateDirectory);
if (cmakeAppPath.isEmpty())
{
return AZ::Failure(QObject::tr("CMake.app not found.") + cmakeHelp);
}
QString projectBuildPath = QDir(projectPath).filePath(ProjectBuildPathPostfix);
AZ::Outcome result = GetProjectBuildPath(projectPath);
if (result.IsSuccess())
{
projectBuildPath = result.GetValue();
}
QProcess process;
// if the project build path is relative, it should be relative to the project path
process.setWorkingDirectory(projectPath);
process.setProgram("open");
process.setArguments({"-a", "CMake", "--args", "-S", projectPath, "-B", projectBuildPath});
if(!process.startDetached())
{
return AZ::Failure(QObject::tr("CMake.app failed to open.") + cmakeHelp);
}
return AZ::Success();
}
} // namespace ProjectUtils } // namespace ProjectUtils
} // namespace O3DE::ProjectManager } // namespace O3DE::ProjectManager

@ -92,12 +92,43 @@ namespace O3DE::ProjectManager
} }
} }
return AZ::Failure(QObject::tr("Visual Studio 2019 version 16.9.2 or higher not found.\n\n" return AZ::Failure(QObject::tr("Visual Studio 2019 version 16.9.2 or higher not found.<br><br>"
"Visual Studio 2019 is required to build this project." "Visual Studio 2019 is required to build this project."
" Install any edition of <a href='https://visualstudio.microsoft.com/downloads/'>Visual Studio 2019</a>" " Install any edition of <a href='https://visualstudio.microsoft.com/downloads/'>Visual Studio 2019</a>"
" or update to a newer version before proceeding to the next step." " or update to a newer version before proceeding to the next step."
" While installing configure Visual Studio with these <a href='https://o3de.org/docs/welcome-guide/setup/requirements/#visual-studio-configuration'>workloads</a>.")); " While installing configure Visual Studio with these <a href='https://o3de.org/docs/welcome-guide/setup/requirements/#visual-studio-configuration'>workloads</a>."));
} }
AZ::Outcome<void, QString> OpenCMakeGUI(const QString& projectPath)
{
AZ::Outcome processEnvResult = GetCommandLineProcessEnvironment();
if (!processEnvResult.IsSuccess())
{
return AZ::Failure(processEnvResult.GetError());
}
QString projectBuildPath = QDir(projectPath).filePath(ProjectBuildPathPostfix);
AZ::Outcome projectBuildPathResult = GetProjectBuildPath(projectPath);
if (projectBuildPathResult.IsSuccess())
{
projectBuildPath = projectBuildPathResult.GetValue();
}
QProcess process;
process.setProcessEnvironment(processEnvResult.GetValue());
// if the project build path is relative, it should be relative to the project path
process.setWorkingDirectory(projectPath);
process.setProgram("cmake-gui");
process.setArguments({ "-S", projectPath, "-B", projectBuildPath });
if(!process.startDetached())
{
return AZ::Failure(QObject::tr("Failed to start CMake GUI"));
}
return AZ::Success();
}
} // namespace ProjectUtils } // namespace ProjectUtils
} // namespace O3DE::ProjectManager } // namespace O3DE::ProjectManager

@ -438,6 +438,11 @@ QTabBar::tab:focus {
max-height:26px; max-height:26px;
} }
#projectActionButton, #openEditorButton {
min-height:26px;
max-height:26px;
}
#labelButtonOverlay { #labelButtonOverlay {
background-color: rgba(50,50,50,200); background-color: rgba(50,50,50,200);
min-width:210px; min-width:210px;

@ -1,5 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="24" height="24" fill="#444444"/>
<rect x="10" y="6" width="4" height="15" fill="black"/> <rect x="10" y="6" width="4" height="15" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 2L22 22H2L12 2ZM13 20V18H11V20H13ZM13 7H11V16.0862H13V7Z" fill="#F0C32D"/> <path fill-rule="evenodd" clip-rule="evenodd" d="M12 2L22 22H2L12 2ZM13 20V18H11V20H13ZM13 7H11V16.0862H13V7Z" fill="#F0C32D"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 333 B

After

Width:  |  Height:  |  Size: 287 B

@ -88,6 +88,7 @@ namespace O3DE::ProjectManager
QHBoxLayout* horizontalButtonLayout = new QHBoxLayout(); QHBoxLayout* horizontalButtonLayout = new QHBoxLayout();
horizontalButtonLayout->addSpacing(34); horizontalButtonLayout->addSpacing(34);
m_actionButton = new QPushButton(tr("Project Action"), this); m_actionButton = new QPushButton(tr("Project Action"), this);
m_actionButton->setObjectName("projectActionButton");
m_actionButton->setVisible(false); m_actionButton->setVisible(false);
horizontalButtonLayout->addWidget(m_actionButton); horizontalButtonLayout->addWidget(m_actionButton);
horizontalButtonLayout->addSpacing(34); horizontalButtonLayout->addSpacing(34);
@ -198,6 +199,7 @@ namespace O3DE::ProjectManager
QMenu* menu = new QMenu(this); QMenu* menu = new QMenu(this);
menu->addAction(tr("Edit Project Settings..."), this, [this]() { emit EditProject(m_projectInfo.m_path); }); 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->addAction(tr("Build"), this, [this]() { emit BuildProject(m_projectInfo); });
menu->addAction(tr("Open CMake GUI..."), this, [this]() { emit OpenCMakeGUI(m_projectInfo); });
menu->addSeparator(); menu->addSeparator();
menu->addAction(tr("Open Project folder..."), this, [this]() menu->addAction(tr("Open Project folder..."), this, [this]()
{ {
@ -259,15 +261,39 @@ namespace O3DE::ProjectManager
} }
projectActionButton->setText(text); projectActionButton->setText(text);
projectActionButton->setMenu(nullptr);
m_actionButtonConnection = connect(projectActionButton, &QPushButton::clicked, lambda); m_actionButtonConnection = connect(projectActionButton, &QPushButton::clicked, lambda);
} }
void ProjectButton::SetProjectBuildButtonAction() void ProjectButton::ShowDefaultBuildButton()
{ {
m_projectImageLabel->GetWarningLabel()->setText(tr("Building project required.")); QPushButton* projectActionButton = m_projectImageLabel->GetActionButton();
m_projectImageLabel->GetWarningIcon()->setVisible(true); projectActionButton->setVisible(true);
m_projectImageLabel->GetWarningLabel()->setVisible(true); projectActionButton->setText(tr("Build Project"));
SetProjectButtonAction(tr("Build Project"), [this]() { emit BuildProject(m_projectInfo); }); disconnect(m_actionButtonConnection);
QMenu* menu = new QMenu(this);
QAction* autoBuildAction = menu->addAction(tr("Build Now"));
connect( autoBuildAction, &QAction::triggered, this, [this](){ emit BuildProject(m_projectInfo); });
QAction* openCMakeAction = menu->addAction(tr("Open CMake GUI..."));
connect( openCMakeAction, &QAction::triggered, this, [this](){ emit OpenCMakeGUI(m_projectInfo); });
projectActionButton->setMenu(menu);
}
void ProjectButton::ShowBuildRequired()
{
ShowWarning(true, tr("Building project required"));
ShowDefaultBuildButton();
}
void ProjectButton::ShowWarning(bool show, const QString& warning)
{
m_projectImageLabel->GetWarningLabel()->setTextInteractionFlags(Qt::LinksAccessibleByMouse);
m_projectImageLabel->GetWarningLabel()->setText(warning);
m_projectImageLabel->GetWarningLabel()->setVisible(show);
m_projectImageLabel->GetWarningIcon()->setVisible(show);
} }
void ProjectButton::SetBuildLogsLink(const QUrl& logUrl) void ProjectButton::SetBuildLogsLink(const QUrl& logUrl)
@ -279,18 +305,15 @@ namespace O3DE::ProjectManager
{ {
if (!logUrl.isEmpty()) if (!logUrl.isEmpty())
{ {
m_projectImageLabel->GetWarningLabel()->setText(tr("Failed to build. Click to <a href=\"logs\">view logs</a>.")); ShowWarning(show, tr("Failed to build. Click to <a href=\"logs\">view logs</a>."));
} }
else else
{ {
m_projectImageLabel->GetWarningLabel()->setText(tr("Project failed to build.")); ShowWarning(show, tr("Project failed to build."));
} }
m_projectImageLabel->GetWarningLabel()->setTextInteractionFlags(Qt::LinksAccessibleByMouse); SetBuildLogsLink(logUrl);
m_projectImageLabel->GetWarningIcon()->setVisible(show); ShowDefaultBuildButton();
m_projectImageLabel->GetWarningLabel()->setVisible(show);
m_projectImageLabel->SetLogUrl(logUrl);
SetProjectButtonAction(tr("Build Project"), [this]() { emit BuildProject(m_projectInfo); });
} }
void ProjectButton::SetProjectBuilding() void ProjectButton::SetProjectBuilding()

@ -82,9 +82,9 @@ namespace O3DE::ProjectManager
void RestoreDefaultState(); void RestoreDefaultState();
void SetProjectButtonAction(const QString& text, AZStd::function<void()> lambda); void SetProjectButtonAction(const QString& text, AZStd::function<void()> lambda);
void SetProjectBuildButtonAction();
void SetBuildLogsLink(const QUrl& logUrl); void SetBuildLogsLink(const QUrl& logUrl);
void ShowBuildFailed(bool show, const QUrl& logUrl); void ShowBuildFailed(bool show, const QUrl& logUrl);
void ShowBuildRequired();
void SetProjectBuilding(); void SetProjectBuilding();
void SetLaunchButtonEnabled(bool enabled); void SetLaunchButtonEnabled(bool enabled);
@ -99,10 +99,13 @@ namespace O3DE::ProjectManager
void RemoveProject(const QString& projectName); void RemoveProject(const QString& projectName);
void DeleteProject(const QString& projectName); void DeleteProject(const QString& projectName);
void BuildProject(const ProjectInfo& projectInfo); void BuildProject(const ProjectInfo& projectInfo);
void OpenCMakeGUI(const ProjectInfo& projectInfo);
private: private:
void enterEvent(QEvent* event) override; void enterEvent(QEvent* event) override;
void leaveEvent(QEvent* event) override; void leaveEvent(QEvent* event) override;
void ShowWarning(bool show, const QString& warning);
void ShowDefaultBuildButton();
ProjectInfo m_projectInfo; ProjectInfo m_projectInfo;

@ -9,6 +9,8 @@
#include <ProjectUtils.h> #include <ProjectUtils.h>
#include <ProjectManagerDefs.h> #include <ProjectManagerDefs.h>
#include <PythonBindingsInterface.h> #include <PythonBindingsInterface.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzCore/IO/Path/Path.h>
#include <QFileDialog> #include <QFileDialog>
#include <QDir> #include <QDir>
@ -537,5 +539,33 @@ namespace O3DE::ProjectManager
QString resultOutput = execProcess.readAllStandardOutput(); QString resultOutput = execProcess.readAllStandardOutput();
return AZ::Success(resultOutput); return AZ::Success(resultOutput);
} }
AZ::Outcome<QString, QString> GetProjectBuildPath(const QString& projectPath)
{
auto registry = AZ::SettingsRegistry::Get();
// the project_build_path should be in the user settings registry inside the project folder
AZ::IO::FixedMaxPath projectUserPath(projectPath.toUtf8().constData());
projectUserPath /= AZ::SettingsRegistryInterface::DevUserRegistryFolder;
if (!QDir(projectUserPath.c_str()).exists())
{
return AZ::Failure(QObject::tr("Failed to find the user registry folder %1").arg(projectUserPath.c_str()));
}
AZ::SettingsRegistryInterface::Specializations specializations;
if(!registry->MergeSettingsFolder(projectUserPath.Native(), specializations, AZ_TRAIT_OS_PLATFORM_CODENAME))
{
return AZ::Failure(QObject::tr("Failed to merge registry settings in user registry folder %1").arg(projectUserPath.c_str()));
}
AZ::IO::FixedMaxPath projectBuildPath;
if (!registry->Get(projectBuildPath.Native(), AZ::SettingsRegistryMergeUtils::ProjectBuildPath))
{
return AZ::Failure(QObject::tr("No project build path setting was found in the user registry folder %1").arg(projectUserPath.c_str()));
}
return AZ::Success(QString(projectBuildPath.c_str()));
}
} // namespace ProjectUtils } // namespace ProjectUtils
} // namespace O3DE::ProjectManager } // namespace O3DE::ProjectManager

@ -42,6 +42,8 @@ namespace O3DE::ProjectManager
int commandTimeoutSeconds = ProjectCommandLineTimeoutSeconds); int commandTimeoutSeconds = ProjectCommandLineTimeoutSeconds);
AZ::Outcome<QProcessEnvironment, QString> GetCommandLineProcessEnvironment(); AZ::Outcome<QProcessEnvironment, QString> GetCommandLineProcessEnvironment();
AZ::Outcome<QString, QString> GetProjectBuildPath(const QString& projectPath);
AZ::Outcome<void, QString> OpenCMakeGUI(const QString& projectPath);
} // namespace ProjectUtils } // namespace ProjectUtils
} // namespace O3DE::ProjectManager } // namespace O3DE::ProjectManager

@ -185,6 +185,15 @@ namespace O3DE::ProjectManager
connect(projectButton, &ProjectButton::RemoveProject, this, &ProjectsScreen::HandleRemoveProject); connect(projectButton, &ProjectButton::RemoveProject, this, &ProjectsScreen::HandleRemoveProject);
connect(projectButton, &ProjectButton::DeleteProject, this, &ProjectsScreen::HandleDeleteProject); connect(projectButton, &ProjectButton::DeleteProject, this, &ProjectsScreen::HandleDeleteProject);
connect(projectButton, &ProjectButton::BuildProject, this, &ProjectsScreen::QueueBuildProject); connect(projectButton, &ProjectButton::BuildProject, this, &ProjectsScreen::QueueBuildProject);
connect(projectButton, &ProjectButton::OpenCMakeGUI, this,
[this](const ProjectInfo& projectInfo)
{
AZ::Outcome result = ProjectUtils::OpenCMakeGUI(projectInfo.m_path);
if (!result)
{
QMessageBox::critical(this, tr("Failed to open CMake GUI"), result.GetError(), QMessageBox::Ok);
}
});
return projectButton; return projectButton;
} }
@ -308,7 +317,7 @@ namespace O3DE::ProjectManager
} }
else else
{ {
projectIter.value()->SetProjectBuildButtonAction(); projectIter.value()->ShowBuildRequired();
} }
} }
} }

Loading…
Cancel
Save