Hook up Gem Updating and Uninstallation and fix lots of minor bugs between gem catalog and gem repos

Signed-off-by: nggieber <nggieber@amazon.com>
This commit is contained in:
nggieber
2021-11-10 12:33:24 -08:00
parent a253bfc2f5
commit f470351d0c
16 changed files with 206 additions and 73 deletions
@@ -429,6 +429,7 @@ namespace O3DE::ProjectManager
hLayout->addSpacing(16);
QMenu* gemMenu = new QMenu(this);
gemMenu->addAction( tr("Refresh"), [this]() { emit RefreshGems(); });
gemMenu->addAction( tr("Show Gem Repos"), [this]() { emit OpenGemsRepo(); });
gemMenu->addSeparator();
gemMenu->addAction( tr("Add Existing Gem"), [this]() { emit AddGem(); });
@@ -89,6 +89,7 @@ namespace O3DE::ProjectManager
signals:
void AddGem();
void OpenGemsRepo();
void RefreshGems();
private:
AzQtComponents::SearchLineEdit* m_filterLineEdit = nullptr;
@@ -15,6 +15,7 @@
#include <GemCatalog/GemUpdateDialog.h>
#include <GemCatalog/GemUninstallDialog.h>
#include <DownloadController.h>
#include <ProjectUtils.h>
#include <QVBoxLayout>
#include <QHBoxLayout>
@@ -50,6 +51,7 @@ namespace O3DE::ProjectManager
vLayout->addWidget(m_headerWidget);
connect(m_gemModel, &GemModel::gemStatusChanged, this, &GemCatalogScreen::OnGemStatusChanged);
connect(m_headerWidget, &GemCatalogHeaderWidget::RefreshGems, this, &GemCatalogScreen::Refresh);
connect(m_headerWidget, &GemCatalogHeaderWidget::OpenGemsRepo, this, &GemCatalogScreen::HandleOpenGemRepo);
connect(m_headerWidget, &GemCatalogHeaderWidget::AddGem, this, &GemCatalogScreen::OnAddGemClicked);
connect(m_downloadController, &DownloadController::Done, this, &GemCatalogScreen::OnGemDownloadResult);
@@ -235,6 +237,9 @@ namespace O3DE::ProjectManager
// temporary, until we can refresh filter counts
m_proxyModel->ResetFilters();
m_filterWidget->ResetAllFilters();
// Reselect the same selection to proc UI updates
m_proxyModel->GetSelectionModel()->select(m_proxyModel->GetSelectionModel()->selection(), QItemSelectionModel::Select);
}
void GemCatalogScreen::OnGemStatusChanged(const QString& gemName, uint32_t numChangedDependencies)
@@ -300,21 +305,83 @@ namespace O3DE::ProjectManager
void GemCatalogScreen::UpdateGem(const QModelIndex& modelIndex)
{
const QString selectedGemName = m_gemModel->GetDisplayName(modelIndex);
GemUpdateDialog* confirmUpdateDialog = new GemUpdateDialog(selectedGemName, this);
const QString selectedGemName = m_gemModel->GetName(modelIndex);
const QString selectedGemLastUpdate = m_gemModel->GetLastUpdated(modelIndex);
const QString selectedDisplayGemName = m_gemModel->GetDisplayName(modelIndex);
const QString selectedGemRepoUri = m_gemModel->GetRepoUri(modelIndex);
// Refresh gem repo
if (!selectedGemRepoUri.isEmpty())
{
AZ::Outcome<void, AZStd::string> refreshResult = PythonBindingsInterface::Get()->RefreshGemRepo(selectedGemRepoUri);
if (refreshResult.IsSuccess())
{
Refresh();
}
else
{
QMessageBox::critical(
this, tr("Operation failed"),
tr("Failed to refresh gem repo %1<br>Error:<br>%2").arg(selectedGemRepoUri, refreshResult.GetError().c_str()));
}
}
// If repo uri isn't specified warn user that repo might not be refreshed
else
{
int result = QMessageBox::warning(
this, tr("Gem Repo Unspecified"),
tr("The repo for %1 is unspecfied. Repo cannot be automatically refreshed. "
"Please ensure this gem's repo is refreshed before attempting to update.")
.arg(selectedDisplayGemName),
QMessageBox::Cancel, QMessageBox::Ok);
// Allow user to cancel update to manually refresh repo
if (result != QMessageBox::Ok)
{
return;
}
}
// Check if there is an update avaliable now that repo is refreshed
bool updateAvaliable = PythonBindingsInterface::Get()->IsGemUpdateAvaliable(selectedGemName, selectedGemLastUpdate);
GemUpdateDialog* confirmUpdateDialog = new GemUpdateDialog(selectedGemName, updateAvaliable, this);
if (confirmUpdateDialog->exec() == QDialog::Accepted)
{
// Update Gem
m_downloadController->AddGemDownload(selectedGemName);
}
}
void GemCatalogScreen::UninstallGem(const QModelIndex& modelIndex)
{
const QString selectedGemName = m_gemModel->GetDisplayName(modelIndex);
GemUninstallDialog* confirmUninstallDialog = new GemUninstallDialog(selectedGemName, this);
const QString selectedDisplayGemName = m_gemModel->GetDisplayName(modelIndex);
GemUninstallDialog* confirmUninstallDialog = new GemUninstallDialog(selectedDisplayGemName, this);
if (confirmUninstallDialog->exec() == QDialog::Accepted)
{
// Uninstall Gem
const QString selectedGemPath = m_gemModel->GetPath(modelIndex);
// Unregister the gem
auto unregisterResult = PythonBindingsInterface::Get()->RegisterGem(selectedGemPath, {}, /*remove*/true);
if (!unregisterResult)
{
QMessageBox::critical(this, tr("Failed to unregister gem"), unregisterResult.GetError().c_str());
}
else
{
// Remove gem from model
m_gemModel->removeRow(modelIndex.row());
// Delete uninstalled gem directory
if (!ProjectUtils::DeleteProjectFiles(selectedGemPath, /*force*/true))
{
QMessageBox::critical(
this, tr("Failed to remove gem directory"), tr("Could not delete gem directory at:<br>%1").arg(selectedGemPath));
}
// Show undownloaded remote gem again
Refresh();
}
}
}
@@ -351,8 +418,10 @@ namespace O3DE::ProjectManager
{
// Add all available gems to the model.
const QVector<GemInfo>& allGemInfos = allGemInfosResult.GetValue();
for (const GemInfo& gemInfo : allGemInfos)
for (GemInfo gemInfo : allGemInfos)
{
// Mark as downloaded because this gem was registered with an existing directory
gemInfo.m_downloadStatus = GemInfo::DownloadStatus::Downloaded;
m_gemModel->AddGem(gemInfo);
}
@@ -85,6 +85,7 @@ namespace O3DE::ProjectManager
QString m_licenseLink;
QString m_directoryLink;
QString m_documentationLink;
QString m_repoUri;
QString m_version = "Unknown Version";
QString m_lastUpdatedDate = "Unknown Date";
int m_binarySizeInKB = 0;
@@ -238,7 +238,7 @@ namespace O3DE::ProjectManager
// Depending gems
m_dependingGems = new GemsSubWidget();
connect(m_dependingGems, &GemsSubWidget::TagClicked, this, [this](const QString& tag){ emit TagClicked(tag); });
connect(m_dependingGems, &GemsSubWidget::TagClicked, this, [this](const Tag& tag){ emit TagClicked(tag); });
m_mainLayout->addWidget(m_dependingGems);
m_mainLayout->addSpacing(20);
@@ -61,6 +61,7 @@ namespace O3DE::ProjectManager
item->setData(gemInfo.m_downloadStatus, RoleDownloadStatus);
item->setData(gemInfo.m_licenseText, RoleLicenseText);
item->setData(gemInfo.m_licenseLink, RoleLicenseLink);
item->setData(gemInfo.m_repoUri, RoleRepoUri);
appendRow(item);
@@ -255,6 +256,11 @@ namespace O3DE::ProjectManager
return modelIndex.data(RoleLicenseLink).toString();
}
QString GemModel::GetRepoUri(const QModelIndex& modelIndex)
{
return modelIndex.data(RoleRepoUri).toString();
}
GemModel* GemModel::GetSourceModel(QAbstractItemModel* model)
{
GemSortFilterProxyModel* proxyModel = qobject_cast<GemSortFilterProxyModel*>(model);
@@ -369,11 +375,30 @@ namespace O3DE::ProjectManager
void GemModel::OnRowsAboutToBeRemoved(const QModelIndex& parent, int first, int last)
{
bool selectedRowRemoved = false;
for (int i = first; i <= last; ++i)
{
QModelIndex modelIndex = index(i, 0, parent);
const QString& gemName = GetName(modelIndex);
m_nameToIndexMap.remove(gemName);
if (GetSelectionModel()->isRowSelected(i))
{
selectedRowRemoved = true;
}
}
// Select a valid row if currently selected row was removed
if (selectedRowRemoved)
{
for (const QModelIndex& index : m_nameToIndexMap)
{
if (index.isValid())
{
GetSelectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
break;
}
}
}
}
@@ -51,7 +51,8 @@ namespace O3DE::ProjectManager
RoleRequirement,
RoleDownloadStatus,
RoleLicenseText,
RoleLicenseLink
RoleLicenseLink,
RoleRepoUri
};
void AddGem(const GemInfo& gemInfo);
@@ -80,6 +81,7 @@ namespace O3DE::ProjectManager
static QString GetRequirement(const QModelIndex& modelIndex);
static QString GetLicenseText(const QModelIndex& modelIndex);
static QString GetLicenseLink(const QModelIndex& modelIndex);
static QString GetRepoUri(const QModelIndex& modelIndex);
static GemModel* GetSourceModel(QAbstractItemModel* model);
static const GemModel* GetSourceModel(const QAbstractItemModel* model);
@@ -39,10 +39,10 @@ namespace O3DE::ProjectManager
QLabel* bodyLabel = new QLabel(tr("The Gem and its related files will be uninstalled. This does not affect the Gems repository. "
"You can reinstall this Gem from the Catalog, but its contents may be subject to change."));
bodyLabel->setWordWrap(true);
bodyLabel->setFixedWidth(440);
bodyLabel->setFixedSize(QSize(440, 80));
layout->addWidget(bodyLabel);
layout->addSpacing(60);
layout->addSpacing(40);
// Buttons
QDialogButtonBox* dialogButtons = new QDialogButtonBox();
@@ -16,7 +16,7 @@
namespace O3DE::ProjectManager
{
GemUpdateDialog::GemUpdateDialog(const QString& gemName, QWidget* parent)
GemUpdateDialog::GemUpdateDialog(const QString& gemName, bool updateAvaliable, QWidget* parent)
: QDialog(parent)
{
setWindowTitle(tr("Update Remote Gem"));
@@ -30,20 +30,23 @@ namespace O3DE::ProjectManager
setLayout(layout);
// Body
QLabel* subTitleLabel = new QLabel(tr("Update to the latest version of %1?").arg(gemName));
QLabel* subTitleLabel = new QLabel(tr("%1Update to the latest version of %2?").arg(
updateAvaliable ? "" : tr("Force "), gemName));
subTitleLabel->setObjectName("gemCatalogDialogSubTitle");
layout->addWidget(subTitleLabel);
layout->addSpacing(10);
QLabel* bodyLabel = new QLabel(tr("The latest version of this Gem may not be compatible with your engine. "
QLabel* bodyLabel = new QLabel(tr("%1The latest version of this Gem may not be compatible with your engine. "
"Updating this Gem will remove any local changes made to this Gem, "
"and may remove old features that are in use."));
"and may remove old features that are in use.").arg(
updateAvaliable ? "" : tr("No update detected for Gem. "
"This will force a redownload of the gem anyways. ")));
bodyLabel->setWordWrap(true);
bodyLabel->setFixedWidth(440);
bodyLabel->setFixedSize(QSize(440, 80));
layout->addWidget(bodyLabel);
layout->addSpacing(60);
layout->addSpacing(40);
// Buttons
QDialogButtonBox* dialogButtons = new QDialogButtonBox();
@@ -52,7 +55,8 @@ namespace O3DE::ProjectManager
QPushButton* cancelButton = dialogButtons->addButton(tr("Cancel"), QDialogButtonBox::RejectRole);
cancelButton->setProperty("secondary", true);
QPushButton* updateButton = dialogButtons->addButton(tr("Update Gem"), QDialogButtonBox::ApplyRole);
QPushButton* updateButton =
dialogButtons->addButton(tr("%1Update Gem").arg(updateAvaliable ? "" : tr("Force ")), QDialogButtonBox::ApplyRole);
connect(cancelButton, &QPushButton::clicked, this, &QDialog::reject);
connect(updateButton, &QPushButton::clicked, this, &QDialog::accept);
@@ -19,7 +19,7 @@ namespace O3DE::ProjectManager
{
Q_OBJECT // AUTOMOC
public :
explicit GemUpdateDialog(const QString& gemName, QWidget* parent = nullptr);
explicit GemUpdateDialog(const QString& gemName, bool updateAvaliable = true, QWidget* parent = nullptr);
~GemUpdateDialog() = default;
};
} // namespace O3DE::ProjectManager