Merge branch 'development' into Prism/RefreshGemRepos

This commit is contained in:
nggieber
2021-10-22 07:44:37 -07:00
442 changed files with 9901 additions and 5876 deletions
@@ -49,6 +49,8 @@ namespace O3DE::ProjectManager
m_stack->addWidget(m_gemCatalogScreen);
vLayout->addWidget(m_stack);
connect(m_gemCatalogScreen, &ScreenWidget::ChangeScreenRequest, this, &CreateProjectCtrl::OnChangeScreenRequest);
// When there are multiple project templates present, we re-gather the gems when changing the selected the project template.
connect(m_newProjectSettingsScreen, &NewProjectSettingsScreen::OnTemplateSelectionChanged, this, [=](int oldIndex, [[maybe_unused]] int newIndex)
{
@@ -133,7 +135,7 @@ namespace O3DE::ProjectManager
}
else
{
emit GotoPreviousScreenRequest();
emit GoToPreviousScreenRequest();
}
}
@@ -0,0 +1,84 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <DownloadController.h>
#include <DownloadWorker.h>
#include <QMessageBox>
namespace O3DE::ProjectManager
{
DownloadController::DownloadController(QWidget* parent)
: QObject()
, m_lastProgress(0)
, m_parent(parent)
{
m_worker = new DownloadWorker();
m_worker->moveToThread(&m_workerThread);
connect(&m_workerThread, &QThread::started, m_worker, &DownloadWorker::StartDownload);
connect(m_worker, &DownloadWorker::Done, this, &DownloadController::HandleResults);
connect(m_worker, &DownloadWorker::UpdateProgress, this, &DownloadController::UpdateUIProgress);
connect(this, &DownloadController::StartGemDownload, m_worker, &DownloadWorker::StartDownload);
}
DownloadController::~DownloadController()
{
connect(&m_workerThread, &QThread::finished, m_worker, &DownloadController::deleteLater);
m_workerThread.requestInterruption();
m_workerThread.quit();
m_workerThread.wait();
}
void DownloadController::AddGemDownload(const QString& gemName)
{
m_gemNames.push_back(gemName);
if (m_gemNames.size() == 1)
{
m_worker->SetGemToDownload(m_gemNames[0], false);
m_workerThread.start();
}
}
void DownloadController::UpdateUIProgress(int progress)
{
m_lastProgress = progress;
emit GemDownloadProgress(progress);
}
void DownloadController::HandleResults(const QString& result)
{
bool succeeded = true;
if (!result.isEmpty())
{
QMessageBox::critical(nullptr, tr("Gem download"), result);
succeeded = false;
}
m_gemNames.erase(m_gemNames.begin());
emit Done(succeeded);
if (!m_gemNames.empty())
{
emit StartGemDownload(m_gemNames[0]);
}
else
{
m_workerThread.quit();
m_workerThread.wait();
}
}
void DownloadController::HandleCancel()
{
m_workerThread.quit();
emit Done(false);
}
} // namespace O3DE::ProjectManager
@@ -0,0 +1,72 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#if !defined(Q_MOC_RUN)
#include <QString>
#include <QThread>
#include <AzCore/std/containers/vector.h>
#endif
QT_FORWARD_DECLARE_CLASS(QProcess)
namespace O3DE::ProjectManager
{
QT_FORWARD_DECLARE_CLASS(DownloadWorker)
class DownloadController : public QObject
{
Q_OBJECT
public:
explicit DownloadController(QWidget* parent = nullptr);
~DownloadController();
void AddGemDownload(const QString& m_gemName);
bool IsDownloadQueueEmpty()
{
return m_gemNames.empty();
}
const AZStd::vector<QString>& GetDownloadQueue() const
{
return m_gemNames;
}
const QString& GetCurrentDownloadingGem() const
{
if (!m_gemNames.empty())
{
return m_gemNames[0];
}
else
{
static const QString emptyString;
return emptyString;
}
}
public slots:
void UpdateUIProgress(int progress);
void HandleResults(const QString& result);
void HandleCancel();
signals:
void StartGemDownload(const QString& gemName);
void Done(bool success = true);
void GemDownloadProgress(int percentage);
private:
DownloadWorker* m_worker;
QThread m_workerThread;
QWidget* m_parent;
AZStd::vector<QString> m_gemNames;
int m_lastProgress;
};
} // namespace O3DE::ProjectManager
@@ -0,0 +1,48 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <DownloadController.h>
#include <DownloadWorker.h>
#include <PythonBindings.h>
namespace O3DE::ProjectManager
{
DownloadWorker::DownloadWorker()
: QObject()
{
}
void DownloadWorker::StartDownload()
{
auto gemDownloadProgress = [=](int downloadProgress)
{
m_downloadProgress = downloadProgress;
emit UpdateProgress(downloadProgress);
};
AZ::Outcome<void, AZStd::string> gemInfoResult = PythonBindingsInterface::Get()->DownloadGem(m_gemName, gemDownloadProgress);
if (gemInfoResult.IsSuccess())
{
emit Done("");
}
else
{
emit Done(tr("Gem download failed"));
}
}
void DownloadWorker::SetGemToDownload(const QString& gemName, bool downloadNow)
{
m_gemName = gemName;
if (downloadNow)
{
StartDownload();
}
}
} // namespace O3DE::ProjectManager
@@ -0,0 +1,42 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#if !defined(Q_MOC_RUN)
#include <AzCore/Outcome/Outcome.h>
#endif
QT_FORWARD_DECLARE_CLASS(QProcess)
namespace O3DE::ProjectManager
{
class DownloadWorker : public QObject
{
// Download was cancelled
inline static const QString DownloadCancelled = QObject::tr("Download Cancelled.");
Q_OBJECT
public:
explicit DownloadWorker();
~DownloadWorker() = default;
public slots:
void StartDownload();
void SetGemToDownload(const QString& gemName, bool downloadNow = true);
signals:
void UpdateProgress(int progress);
void Done(QString result = "");
private:
QString m_gemName;
int m_downloadProgress;
};
} // namespace O3DE::ProjectManager
@@ -29,17 +29,17 @@ namespace O3DE::ProjectManager
topBarFrameWidget->setLayout(topBarHLayout);
QTabWidget* tabWidget = new QTabWidget();
tabWidget->setObjectName("engineTab");
tabWidget->tabBar()->setObjectName("engineTabBar");
tabWidget->tabBar()->setFocusPolicy(Qt::TabFocus);
m_tabWidget = new QTabWidget();
m_tabWidget->setObjectName("engineTab");
m_tabWidget->tabBar()->setObjectName("engineTabBar");
m_tabWidget->tabBar()->setFocusPolicy(Qt::TabFocus);
m_engineSettingsScreen = new EngineSettingsScreen();
m_gemRepoScreen = new GemRepoScreen();
tabWidget->addTab(m_engineSettingsScreen, tr("General"));
tabWidget->addTab(m_gemRepoScreen, tr("Gem Repositories"));
topBarHLayout->addWidget(tabWidget);
m_tabWidget->addTab(m_engineSettingsScreen, tr("General"));
m_tabWidget->addTab(m_gemRepoScreen, tr("Gem Repositories"));
topBarHLayout->addWidget(m_tabWidget);
vLayout->addWidget(topBarFrameWidget);
@@ -61,4 +61,28 @@ namespace O3DE::ProjectManager
return true;
}
bool EngineScreenCtrl::ContainsScreen(ProjectManagerScreen screen)
{
if (screen == m_engineSettingsScreen->GetScreenEnum() || screen == m_gemRepoScreen->GetScreenEnum())
{
return true;
}
return false;
}
void EngineScreenCtrl::GoToScreen(ProjectManagerScreen screen)
{
if (screen == m_engineSettingsScreen->GetScreenEnum())
{
m_tabWidget->setCurrentWidget(m_engineSettingsScreen);
m_engineSettingsScreen->NotifyCurrentScreen();
}
else if (screen == m_gemRepoScreen->GetScreenEnum())
{
m_tabWidget->setCurrentWidget(m_gemRepoScreen);
m_gemRepoScreen->NotifyCurrentScreen();
}
}
} // namespace O3DE::ProjectManager
@@ -11,6 +11,8 @@
#include <ScreenWidget.h>
#endif
QT_FORWARD_DECLARE_CLASS(QTabWidget)
namespace O3DE::ProjectManager
{
QT_FORWARD_DECLARE_CLASS(EngineSettingsScreen)
@@ -26,7 +28,10 @@ namespace O3DE::ProjectManager
QString GetTabText() override;
bool IsTab() override;
bool ContainsScreen(ProjectManagerScreen screen) override;
void GoToScreen(ProjectManagerScreen screen) override;
QTabWidget* m_tabWidget = nullptr;
EngineSettingsScreen* m_engineSettingsScreen = nullptr;
GemRepoScreen* m_gemRepoScreen = nullptr;
};
@@ -8,17 +8,21 @@
#include <GemCatalog/GemCatalogHeaderWidget.h>
#include <AzCore/std/functional.h>
#include <TagWidget.h>
#include <QHBoxLayout>
#include <QMouseEvent>
#include <QLabel>
#include <QPushButton>
#include <TagWidget.h>
#include <QMenu>
#include <QProgressBar>
namespace O3DE::ProjectManager
{
CartOverlayWidget::CartOverlayWidget(GemModel* gemModel, QWidget* parent)
CartOverlayWidget::CartOverlayWidget(GemModel* gemModel, DownloadController* downloadController, QWidget* parent)
: QWidget(parent)
, m_gemModel(gemModel)
, m_downloadController(downloadController)
{
setObjectName("GemCatalogCart");
@@ -42,6 +46,9 @@ namespace O3DE::ProjectManager
hLayout->addWidget(closeButton);
m_layout->addLayout(hLayout);
// downloading gems
CreateDownloadSection();
// added
CreateGemSection( tr("Gem to be activated"), tr("Gems to be activated"), [=]
{
@@ -149,6 +156,109 @@ namespace O3DE::ProjectManager
update();
}
void CartOverlayWidget::CreateDownloadSection()
{
QWidget* widget = new QWidget();
widget->setFixedWidth(s_width);
m_layout->addWidget(widget);
QVBoxLayout* layout = new QVBoxLayout();
layout->setAlignment(Qt::AlignTop);
widget->setLayout(layout);
QLabel* titleLabel = new QLabel();
titleLabel->setObjectName("GemCatalogCartOverlaySectionLabel");
layout->addWidget(titleLabel);
titleLabel->setText(tr("Gems to be installed"));
// Create header section
QWidget* downloadingGemsWidget = new QWidget();
downloadingGemsWidget->setObjectName("GemCatalogCartOverlayGemDownloadHeader");
layout->addWidget(downloadingGemsWidget);
QVBoxLayout* gemDownloadLayout = new QVBoxLayout();
gemDownloadLayout->setMargin(0);
gemDownloadLayout->setAlignment(Qt::AlignTop);
downloadingGemsWidget->setLayout(gemDownloadLayout);
QLabel* processingQueueLabel = new QLabel("Processing Queue");
gemDownloadLayout->addWidget(processingQueueLabel);
QWidget* downloadingItemWidget = new QWidget();
downloadingItemWidget->setObjectName("GemCatalogCartOverlayGemDownloadBG");
gemDownloadLayout->addWidget(downloadingItemWidget);
QVBoxLayout* downloadingItemLayout = new QVBoxLayout();
downloadingItemLayout->setAlignment(Qt::AlignTop);
downloadingItemWidget->setLayout(downloadingItemLayout);
auto update = [=](int downloadProgress)
{
if (m_downloadController->IsDownloadQueueEmpty())
{
widget->hide();
}
else
{
widget->setUpdatesEnabled(false);
// remove items
QLayoutItem* layoutItem = nullptr;
while ((layoutItem = downloadingItemLayout->takeAt(0)) != nullptr)
{
if (layoutItem->layout())
{
// Gem info row
QLayoutItem* rowLayoutItem = nullptr;
while ((rowLayoutItem = layoutItem->layout()->takeAt(0)) != nullptr)
{
rowLayoutItem->widget()->deleteLater();
}
layoutItem->layout()->deleteLater();
}
if (layoutItem->widget())
{
layoutItem->widget()->deleteLater();
}
}
// Setup gem download rows
const AZStd::vector<QString>& downloadQueue = m_downloadController->GetDownloadQueue();
QLabel* downloadsInProgessLabel = new QLabel("");
downloadsInProgessLabel->setText(
QString("%1 %2").arg(downloadQueue.size()).arg(downloadQueue.size() == 1 ? tr("download in progress...") : tr("downloads in progress...")));
downloadingItemLayout->addWidget(downloadsInProgessLabel);
for (int downloadingGemNumber = 0; downloadingGemNumber < downloadQueue.size(); ++downloadingGemNumber)
{
QHBoxLayout* nameProgressLayout = new QHBoxLayout();
TagWidget* newTag = new TagWidget(downloadQueue[downloadingGemNumber]);
nameProgressLayout->addWidget(newTag);
QLabel* progress = new QLabel(downloadingGemNumber == 0? QString("%1%").arg(downloadProgress) : tr("Queued"));
nameProgressLayout->addWidget(progress);
QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum);
nameProgressLayout->addSpacerItem(spacer);
QLabel* cancelText = new QLabel(tr("Cancel"));
nameProgressLayout->addWidget(cancelText);
downloadingItemLayout->addLayout(nameProgressLayout);
QProgressBar* downloadProgessBar = new QProgressBar();
downloadingItemLayout->addWidget(downloadProgessBar);
downloadProgessBar->setValue(downloadingGemNumber == 0 ? downloadProgress : 0);
}
widget->setUpdatesEnabled(true);
widget->show();
}
};
auto downloadEnded = [=](bool /*success*/)
{
update(0); // update the list to remove the gem that has finished
};
// connect to download controller data changed
connect(m_downloadController, &DownloadController::GemDownloadProgress, this, update);
connect(m_downloadController, &DownloadController::Done, this, downloadEnded);
update(0);
}
QStringList CartOverlayWidget::ConvertFromModelIndices(const QVector<QModelIndex>& gems) const
{
QStringList gemNames;
@@ -160,9 +270,10 @@ namespace O3DE::ProjectManager
return gemNames;
}
CartButton::CartButton(GemModel* gemModel, QWidget* parent)
CartButton::CartButton(GemModel* gemModel, DownloadController* downloadController, QWidget* parent)
: QWidget(parent)
, m_gemModel(gemModel)
, m_downloadController(downloadController)
{
m_layout = new QHBoxLayout();
m_layout->setMargin(0);
@@ -239,7 +350,7 @@ namespace O3DE::ProjectManager
delete m_cartOverlay;
}
m_cartOverlay = new CartOverlayWidget(m_gemModel, this);
m_cartOverlay = new CartOverlayWidget(m_gemModel, m_downloadController, this);
connect(m_cartOverlay, &QWidget::destroyed, this, [=]
{
// Reset the overlay pointer on destruction to prevent dangling pointers.
@@ -265,7 +376,7 @@ namespace O3DE::ProjectManager
}
}
GemCatalogHeaderWidget::GemCatalogHeaderWidget(GemModel* gemModel, GemSortFilterProxyModel* filterProxyModel, QWidget* parent)
GemCatalogHeaderWidget::GemCatalogHeaderWidget(GemModel* gemModel, GemSortFilterProxyModel* filterProxyModel, DownloadController* downloadController, QWidget* parent)
: QFrame(parent)
{
QHBoxLayout* hLayout = new QHBoxLayout();
@@ -293,8 +404,30 @@ namespace O3DE::ProjectManager
hLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding));
hLayout->addSpacerItem(new QSpacerItem(75, 0, QSizePolicy::Fixed));
CartButton* cartButton = new CartButton(gemModel);
CartButton* cartButton = new CartButton(gemModel, downloadController);
hLayout->addWidget(cartButton);
hLayout->addSpacing(16);
// Separating line
QFrame* vLine = new QFrame();
vLine->setFrameShape(QFrame::VLine);
vLine->setObjectName("verticalSeparatingLine");
hLayout->addWidget(vLine);
hLayout->addSpacing(16);
QMenu* gemMenu = new QMenu(this);
m_openGemReposAction = gemMenu->addAction(tr("Show Gem Repos"));
connect(m_openGemReposAction, &QAction::triggered, this,[this](){ emit OpenGemsRepo(); });
QPushButton* gemMenuButton = new QPushButton(this);
gemMenuButton->setObjectName("gemCatalogMenuButton");
gemMenuButton->setMenu(gemMenu);
gemMenuButton->setIcon(QIcon(":/menu.svg"));
gemMenuButton->setIconSize(QSize(36, 24));
hLayout->addWidget(gemMenuButton);
}
void GemCatalogHeaderWidget::ReinitForProject()
@@ -15,12 +15,15 @@
#include <GemCatalog/GemModel.h>
#include <GemCatalog/GemSortFilterProxyModel.h>
#include <TagWidget.h>
#include <DownloadController.h>
#include <QFrame>
#include <QLabel>
#include <QDialog>
#include <QMoveEvent>
#include <QHideEvent>
#include <QVBoxLayout>
#include <QAction>
#endif
namespace O3DE::ProjectManager
@@ -31,16 +34,18 @@ namespace O3DE::ProjectManager
Q_OBJECT // AUTOMOC
public:
CartOverlayWidget(GemModel* gemModel, QWidget* parent = nullptr);
CartOverlayWidget(GemModel* gemModel, DownloadController* downloadController, QWidget* parent = nullptr);
private:
QStringList ConvertFromModelIndices(const QVector<QModelIndex>& gems) const;
using GetTagIndicesCallback = AZStd::function<QVector<QModelIndex>()>;
void CreateGemSection(const QString& singularTitle, const QString& pluralTitle, GetTagIndicesCallback getTagIndices);
void CreateDownloadSection();
QVBoxLayout* m_layout = nullptr;
GemModel* m_gemModel = nullptr;
DownloadController* m_downloadController = nullptr;
inline constexpr static int s_width = 240;
};
@@ -51,7 +56,7 @@ namespace O3DE::ProjectManager
Q_OBJECT // AUTOMOC
public:
CartButton(GemModel* gemModel, QWidget* parent = nullptr);
CartButton(GemModel* gemModel, DownloadController* downloadController, QWidget* parent = nullptr);
~CartButton();
void ShowOverlay();
@@ -64,6 +69,7 @@ namespace O3DE::ProjectManager
QLabel* m_countLabel = nullptr;
QPushButton* m_dropDownButton = nullptr;
CartOverlayWidget* m_cartOverlay = nullptr;
DownloadController* m_downloadController = nullptr;
inline constexpr static int s_iconSize = 24;
inline constexpr static int s_arrowDownIconSize = 8;
@@ -75,13 +81,18 @@ namespace O3DE::ProjectManager
Q_OBJECT // AUTOMOC
public:
explicit GemCatalogHeaderWidget(GemModel* gemModel, GemSortFilterProxyModel* filterProxyModel, QWidget* parent = nullptr);
explicit GemCatalogHeaderWidget(GemModel* gemModel, GemSortFilterProxyModel* filterProxyModel, DownloadController* downloadController, QWidget* parent = nullptr);
~GemCatalogHeaderWidget() = default;
void ReinitForProject();
signals:
void OpenGemsRepo();
private:
AzQtComponents::SearchLineEdit* m_filterLineEdit = nullptr;
inline constexpr static int s_height = 60;
QAction* m_openGemReposAction = nullptr;
};
} // namespace O3DE::ProjectManager
@@ -12,6 +12,7 @@
#include <GemCatalog/GemSortFilterProxyModel.h>
#include <GemCatalog/GemRequirementDialog.h>
#include <GemCatalog/GemDependenciesDialog.h>
#include <DownloadController.h>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
@@ -32,9 +33,13 @@ namespace O3DE::ProjectManager
vLayout->setSpacing(0);
setLayout(vLayout);
m_headerWidget = new GemCatalogHeaderWidget(m_gemModel, m_proxModel);
m_downloadController = new DownloadController();
m_headerWidget = new GemCatalogHeaderWidget(m_gemModel, m_proxModel, m_downloadController);
vLayout->addWidget(m_headerWidget);
connect(m_headerWidget, &GemCatalogHeaderWidget::OpenGemsRepo, this, &GemCatalogScreen::HandleOpenGemRepo);
QHBoxLayout* hLayout = new QHBoxLayout();
hLayout->setMargin(0);
vLayout->addLayout(hLayout);
@@ -191,6 +196,27 @@ namespace O3DE::ProjectManager
return EnableDisableGemsResult::Success;
}
void GemCatalogScreen::HandleOpenGemRepo()
{
QVector<QModelIndex> gemsToBeAdded = m_gemModel->GatherGemsToBeAdded(true);
QVector<QModelIndex> gemsToBeRemoved = m_gemModel->GatherGemsToBeRemoved(true);
if (!gemsToBeAdded.empty() || !gemsToBeRemoved.empty())
{
QMessageBox::StandardButton warningResult = QMessageBox::warning(
nullptr, "Pending Changes",
"There are some unsaved changes to the gem selection,<br> they will be lost if you change screens.<br> Are you sure?",
QMessageBox::No | QMessageBox::Yes);
if (warningResult != QMessageBox::Yes)
{
return;
}
}
emit ChangeScreenRequest(ProjectManagerScreen::GemRepos);
}
ProjectManagerScreen GemCatalogScreen::GetScreenEnum()
{
return ProjectManagerScreen::GemCatalog;
@@ -39,8 +39,13 @@ namespace O3DE::ProjectManager
EnableDisableGemsResult EnableDisableGemsForProject(const QString& projectPath);
GemModel* GetGemModel() const { return m_gemModel; }
DownloadController* GetDownloadController() const { return m_downloadController; }
private slots:
void HandleOpenGemRepo();
private:
void FillModel(const QString& projectPath);
GemListView* m_gemListView = nullptr;
@@ -50,5 +55,6 @@ namespace O3DE::ProjectManager
GemSortFilterProxyModel* m_proxModel = nullptr;
QVBoxLayout* m_filterWidgetLayout = nullptr;
GemFilterWidget* m_filterWidget = nullptr;
DownloadController* m_downloadController = nullptr;
};
} // namespace O3DE::ProjectManager
@@ -301,6 +301,7 @@ namespace O3DE::ProjectManager
m_enableGemProject = pybind11::module::import("o3de.enable_gem");
m_disableGemProject = pybind11::module::import("o3de.disable_gem");
m_editProjectProperties = pybind11::module::import("o3de.project_properties");
m_download = pybind11::module::import("o3de.download");
m_repo = pybind11::module::import("o3de.repo");
m_pathlib = pybind11::module::import("pathlib");
@@ -1116,4 +1117,30 @@ namespace O3DE::ProjectManager
std::sort(gemRepos.begin(), gemRepos.end());
return AZ::Success(AZStd::move(gemRepos));
}
AZ::Outcome<void, AZStd::string> PythonBindings::DownloadGem(const QString& gemName, std::function<void(int)> gemProgressCallback)
{
bool downloadSucceeded = false;
auto result = ExecuteWithLockErrorHandling(
[&]
{
auto downloadResult = m_download.attr("download_gem")(
QString_To_Py_String(gemName), // gem name
pybind11::none(), // destination path
false// skip auto register
);
downloadSucceeded = (downloadResult.cast<int>() == 0);
});
if (!result.IsSuccess())
{
return result;
}
else if (!downloadSucceeded)
{
return AZ::Failure<AZStd::string>("Failed to download gem.");
}
return AZ::Success();
}
}
@@ -63,6 +63,7 @@ namespace O3DE::ProjectManager
bool AddGemRepo(const QString& repoUri) override;
bool RemoveGemRepo(const QString& repoUri) override;
AZ::Outcome<QVector<GemRepoInfo>, AZStd::string> GetAllGemRepoInfos() override;
AZ::Outcome<void, AZStd::string> DownloadGem(const QString& gemName, std::function<void(int)> gemProgressCallback) override;
private:
AZ_DISABLE_COPY_MOVE(PythonBindings);
@@ -89,6 +90,7 @@ namespace O3DE::ProjectManager
pybind11::handle m_enableGemProject;
pybind11::handle m_disableGemProject;
pybind11::handle m_editProjectProperties;
pybind11::handle m_download;
pybind11::handle m_repo;
pybind11::handle m_pathlib;
};
@@ -200,6 +200,8 @@ namespace O3DE::ProjectManager
* @return A list of gem repo infos.
*/
virtual AZ::Outcome<QVector<GemRepoInfo>, AZStd::string> GetAllGemRepoInfos() = 0;
virtual AZ::Outcome<void, AZStd::string> DownloadGem(const QString& gemName, std::function<void(int)> gemProgressCallback) = 0;
};
using PythonBindingsInterface = AZ::Interface<IPythonBindings>;
@@ -47,6 +47,14 @@ namespace O3DE::ProjectManager
return tr("Missing");
}
virtual bool ContainsScreen([[maybe_unused]] ProjectManagerScreen screen)
{
return false;
}
virtual void GoToScreen([[maybe_unused]] ProjectManagerScreen screen)
{
}
//! Notify this screen it is the current screen
virtual void NotifyCurrentScreen()
{
@@ -55,7 +63,7 @@ namespace O3DE::ProjectManager
signals:
void ChangeScreenRequest(ProjectManagerScreen screen);
void GotoPreviousScreenRequest();
void GoToPreviousScreenRequest();
void ResetScreenRequest(ProjectManagerScreen screen);
void NotifyCurrentProject(const QString& projectPath);
void NotifyBuildProject(const ProjectInfo& projectInfo);
@@ -83,11 +83,28 @@ namespace O3DE::ProjectManager
bool ScreensCtrl::ForceChangeToScreen(ProjectManagerScreen screen, bool addVisit)
{
ScreenWidget* newScreen = nullptr;
const auto iterator = m_screenMap.find(screen);
if (iterator != m_screenMap.end())
{
newScreen = iterator.value();
}
else
{
// Check if screen is contained by another screen
for (ScreenWidget* checkingScreen : m_screenMap)
{
if (checkingScreen->ContainsScreen(screen))
{
newScreen = checkingScreen;
break;
}
}
}
if (newScreen)
{
ScreenWidget* currentScreen = GetCurrentScreen();
ScreenWidget* newScreen = iterator.value();
if (currentScreen != newScreen)
{
@@ -109,6 +126,11 @@ namespace O3DE::ProjectManager
newScreen->NotifyCurrentScreen();
if (iterator == m_screenMap.end())
{
newScreen->GoToScreen(screen);
}
return true;
}
}
@@ -116,7 +138,7 @@ namespace O3DE::ProjectManager
return false;
}
bool ScreensCtrl::GotoPreviousScreen()
bool ScreensCtrl::GoToPreviousScreen()
{
if (!m_screenVisitOrder.isEmpty())
{
@@ -171,7 +193,7 @@ namespace O3DE::ProjectManager
m_screenMap.insert(screen, newScreen);
connect(newScreen, &ScreenWidget::ChangeScreenRequest, this, &ScreensCtrl::ChangeToScreen);
connect(newScreen, &ScreenWidget::GotoPreviousScreenRequest, this, &ScreensCtrl::GotoPreviousScreen);
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);
@@ -41,7 +41,7 @@ namespace O3DE::ProjectManager
public slots:
bool ChangeToScreen(ProjectManagerScreen screen);
bool ForceChangeToScreen(ProjectManagerScreen screen, bool addVisit = true);
bool GotoPreviousScreen();
bool GoToPreviousScreen();
void ResetScreen(ProjectManagerScreen screen);
void ResetAllScreens();
void DeleteScreen(ProjectManagerScreen screen);
@@ -40,6 +40,10 @@ namespace O3DE::ProjectManager
m_updateSettingsScreen = new UpdateProjectSettingsScreen();
m_gemCatalogScreen = new GemCatalogScreen();
connect(m_gemCatalogScreen, &ScreenWidget::ChangeScreenRequest, this, [this](ProjectManagerScreen screen){
emit ChangeScreenRequest(screen);
});
m_stack = new QStackedWidget(this);
m_stack->setObjectName("body");
m_stack->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding));
@@ -118,7 +122,7 @@ namespace O3DE::ProjectManager
{
if (UpdateProjectSettings(true))
{
emit GotoPreviousScreenRequest();
emit GoToPreviousScreenRequest();
}
}
}
@@ -136,6 +140,11 @@ namespace O3DE::ProjectManager
}
else if (m_stack->currentIndex() == ScreenOrder::Gems && m_gemCatalogScreen)
{
if (!m_gemCatalogScreen->GetDownloadController()->IsDownloadQueueEmpty())
{
QMessageBox::critical(this, tr("Gems downloading"), tr("You must wait for gems to finish downloading before continuing."));
return;
}
// Enable or disable the gems that got adjusted in the gem catalog and apply them to the given project.
const GemCatalogScreen::EnableDisableGemsResult result = m_gemCatalogScreen->EnableDisableGemsForProject(m_projectInfo.m_path);
if (result == GemCatalogScreen::EnableDisableGemsResult::Failed)