Connect Adding and Removal of Gem Repo UI to CLI (#4729)

* Connect Adding and Removal of Gem Repo UI to CLI

Signed-off-by: nggieber <nggieber@amazon.com>

* Addressed PR feedback

Signed-off-by: nggieber <nggieber@amazon.com>
monroegm-disable-blank-issue-2
AMZN-nggieber 4 years ago committed by GitHub
parent e6464335af
commit 4899309b6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -7,7 +7,7 @@
*/
#include <GemRepo/GemRepoAddDialog.h>
#include <FormLineEditWidget.h>
#include <FormFolderBrowseEditWidget.h>
#include <QVBoxLayout>
#include <QLabel>
@ -40,7 +40,7 @@ namespace O3DE::ProjectManager
instructionContextLabel->setAlignment(Qt::AlignLeft);
vLayout->addWidget(instructionContextLabel);
m_repoPath = new FormLineEditWidget(tr("Repository Path"), "", this);
m_repoPath = new FormFolderBrowseEditWidget(tr("Repository Path"), "", this);
m_repoPath->setFixedWidth(600);
vLayout->addWidget(m_repoPath);

@ -36,7 +36,7 @@ namespace O3DE::ProjectManager
QString m_summary = "No summary provided.";
QString m_additionalInfo = "";
QString m_directoryLink = "";
QString m_repoLink = "";
QString m_repoUri = "";
QStringList m_includedGemPaths = {};
QDateTime m_lastUpdated;
};

@ -60,8 +60,8 @@ namespace O3DE::ProjectManager
// Repo name and url link
m_nameLabel->setText(m_model->GetName(modelIndex));
m_repoLinkLabel->setText(m_model->GetRepoLink(modelIndex));
m_repoLinkLabel->SetUrl(m_model->GetRepoLink(modelIndex));
m_repoLinkLabel->setText(m_model->GetRepoUri(modelIndex));
m_repoLinkLabel->SetUrl(m_model->GetRepoUri(modelIndex));
// Repo summary
m_summaryLabel->setText(m_model->GetSummary(modelIndex));

@ -145,6 +145,11 @@ namespace O3DE::ProjectManager
GemRepoModel::SetEnabled(*model, modelIndex, !isAdded);
return true;
}
else if (keyEvent->key() == Qt::Key_X)
{
emit RemoveRepo(modelIndex);
return true;
}
}
if (event->type() == QEvent::MouseButtonPress)
@ -154,6 +159,7 @@ namespace O3DE::ProjectManager
QRect fullRect, itemRect, contentRect;
CalcRects(option, fullRect, itemRect, contentRect);
const QRect buttonRect = CalcButtonRect(contentRect);
const QRect deleteButtonRect = CalcDeleteButtonRect(contentRect);
if (buttonRect.contains(mouseEvent->pos()))
{
@ -161,6 +167,11 @@ namespace O3DE::ProjectManager
GemRepoModel::SetEnabled(*model, modelIndex, !isAdded);
return true;
}
else if (deleteButtonRect.contains(mouseEvent->pos()))
{
emit RemoveRepo(modelIndex);
return true;
}
}
return QStyledItemDelegate::editorEvent(event, model, option, modelIndex);
@ -214,9 +225,14 @@ namespace O3DE::ProjectManager
painter->restore();
}
QRect GemRepoItemDelegate::CalcDeleteButtonRect(const QRect& contentRect) const
{
const QPoint topLeft = QPoint(contentRect.right() - s_iconSize, contentRect.center().y() - s_iconSize / 2);
return QRect(topLeft, QSize(s_iconSize, s_iconSize));
}
void GemRepoItemDelegate::DrawEditButtons(QPainter* painter, const QRect& contentRect) const
{
painter->drawPixmap(contentRect.right() - s_iconSize * 2 - s_iconSpacing, contentRect.center().y() - s_iconSize / 2, m_editIcon);
painter->drawPixmap(contentRect.right() - s_iconSize, contentRect.center().y() - s_iconSize / 2, m_deleteIcon);
}

@ -66,10 +66,14 @@ namespace O3DE::ProjectManager
inline constexpr static int s_refreshIconSize = 14;
inline constexpr static int s_refreshIconSpacing = 10;
signals:
void RemoveRepo(const QModelIndex& modelIndex);
protected:
void CalcRects(const QStyleOptionViewItem& option, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const;
QRect GetTextRect(QFont& font, const QString& text, qreal fontSize) const;
QRect CalcButtonRect(const QRect& contentRect) const;
QRect CalcDeleteButtonRect(const QRect& contentRect) const;
void DrawButton(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const;
void DrawEditButtons(QPainter* painter, const QRect& contentRect) const;

@ -9,6 +9,8 @@
#include <GemRepo/GemRepoListView.h>
#include <GemRepo/GemRepoItemDelegate.h>
#include <QShortcut>
namespace O3DE::ProjectManager
{
GemRepoListView::GemRepoListView(QAbstractItemModel* model, QItemSelectionModel* selectionModel, QWidget* parent)
@ -19,6 +21,9 @@ namespace O3DE::ProjectManager
setModel(model);
setSelectionModel(selectionModel);
setItemDelegate(new GemRepoItemDelegate(model, this));
GemRepoItemDelegate* itemDelegate = new GemRepoItemDelegate(model, this);
connect(itemDelegate, &GemRepoItemDelegate::RemoveRepo, this, &GemRepoListView::RemoveRepo);
setItemDelegate(itemDelegate);
}
} // namespace O3DE::ProjectManager

@ -25,5 +25,8 @@ namespace O3DE::ProjectManager
public:
explicit GemRepoListView(QAbstractItemModel* model, QItemSelectionModel* selectionModel, QWidget* parent = nullptr);
~GemRepoListView() = default;
signals:
void RemoveRepo(const QModelIndex& modelIndex);
};
} // namespace O3DE::ProjectManager

@ -37,7 +37,7 @@ namespace O3DE::ProjectManager
item->setData(gemRepoInfo.m_summary, RoleSummary);
item->setData(gemRepoInfo.m_isEnabled, RoleIsEnabled);
item->setData(gemRepoInfo.m_directoryLink, RoleDirectoryLink);
item->setData(gemRepoInfo.m_repoLink, RoleRepoLink);
item->setData(gemRepoInfo.m_repoUri, RoleRepoUri);
item->setData(gemRepoInfo.m_lastUpdated, RoleLastUpdated);
item->setData(gemRepoInfo.m_path, RolePath);
item->setData(gemRepoInfo.m_additionalInfo, RoleAdditionalInfo);
@ -83,9 +83,9 @@ namespace O3DE::ProjectManager
return modelIndex.data(RoleDirectoryLink).toString();
}
QString GemRepoModel::GetRepoLink(const QModelIndex& modelIndex)
QString GemRepoModel::GetRepoUri(const QModelIndex& modelIndex)
{
return modelIndex.data(RoleRepoLink).toString();
return modelIndex.data(RoleRepoUri).toString();
}
QDateTime GemRepoModel::GetLastUpdated(const QModelIndex& modelIndex)

@ -35,7 +35,7 @@ namespace O3DE::ProjectManager
static QString GetSummary(const QModelIndex& modelIndex);
static QString GetAdditionalInfo(const QModelIndex& modelIndex);
static QString GetDirectoryLink(const QModelIndex& modelIndex);
static QString GetRepoLink(const QModelIndex& modelIndex);
static QString GetRepoUri(const QModelIndex& modelIndex);
static QDateTime GetLastUpdated(const QModelIndex& modelIndex);
static QString GetPath(const QModelIndex& modelIndex);
@ -55,7 +55,7 @@ namespace O3DE::ProjectManager
RoleSummary,
RoleIsEnabled,
RoleDirectoryLink,
RoleRepoLink,
RoleRepoUri,
RoleLastUpdated,
RolePath,
RoleAdditionalInfo,

@ -25,6 +25,7 @@
#include <QTableWidget>
#include <QFrame>
#include <QStackedWidget>
#include <QMessageBox>
namespace O3DE::ProjectManager
{
@ -79,21 +80,48 @@ namespace O3DE::ProjectManager
if (repoAddDialog->exec() == QDialog::DialogCode::Accepted)
{
QString repoUrl = repoAddDialog->GetRepoPath();
if (repoUrl.isEmpty())
QString repoUri = repoAddDialog->GetRepoPath();
if (repoUri.isEmpty())
{
QMessageBox::warning(this, tr("No Input"), tr("Please provide a repo Uri."));
return;
}
AZ::Outcome<void, AZStd::string> addGemRepoResult = PythonBindingsInterface::Get()->AddGemRepo(repoUrl);
if (addGemRepoResult.IsSuccess())
bool addGemRepoResult = PythonBindingsInterface::Get()->AddGemRepo(repoUri);
if (addGemRepoResult)
{
Reinit();
}
else
{
QMessageBox::critical(this, tr("Operation failed"),
QString("Failed to add gem repo: %1.<br>Error:<br>%2").arg(repoUrl, addGemRepoResult.GetError().c_str()));
QString failureMessage = tr("Failed to add gem repo: %1.").arg(repoUri);
QMessageBox::critical(this, tr("Operation failed"), failureMessage);
AZ_Error("Project Manger", false, failureMessage.toUtf8());
}
}
}
void GemRepoScreen::HandleRemoveRepoButton(const QModelIndex& modelIndex)
{
QString repoName = m_gemRepoModel->GetName(modelIndex);
QMessageBox::StandardButton warningResult = QMessageBox::warning(
this, tr("Remove Repo"), tr("Are you sure you would like to remove gem repo: %1?").arg(repoName),
QMessageBox::No | QMessageBox::Yes);
if (warningResult == QMessageBox::Yes)
{
QString repoUri = m_gemRepoModel->GetRepoUri(modelIndex);
bool removeGemRepoResult = PythonBindingsInterface::Get()->RemoveGemRepo(repoUri);
if (removeGemRepoResult)
{
Reinit();
}
else
{
QString failureMessage = tr("Failed to remove gem repo: %1.").arg(repoUri);
QMessageBox::critical(this, tr("Operation failed"), failureMessage);
AZ_Error("Project Manger", false, failureMessage.toUtf8());
}
}
}
@ -251,6 +279,8 @@ namespace O3DE::ProjectManager
m_gemRepoListView = new GemRepoListView(m_gemRepoModel, m_gemRepoModel->GetSelectionModel(), this);
middleVLayout->addWidget(m_gemRepoListView);
connect(m_gemRepoListView, &GemRepoListView::RemoveRepo, this, &GemRepoScreen::HandleRemoveRepoButton);
hLayout->addLayout(middleVLayout);
m_gemRepoInspector = new GemRepoInspector(m_gemRepoModel, this);

@ -39,6 +39,7 @@ namespace O3DE::ProjectManager
public slots:
void HandleAddRepoButton();
void HandleRemoveRepoButton(const QModelIndex& modelIndex);
private:
void FillModel();

@ -939,17 +939,60 @@ namespace O3DE::ProjectManager
}
}
AZ::Outcome<void, AZStd::string> PythonBindings::AddGemRepo(const QString& repoUri)
bool PythonBindings::AddGemRepo(const QString& repoUri)
{
// o3de scripts need method added
(void)repoUri;
return AZ::Failure<AZStd::string>("Adding Gem Repo not implemented yet in o3de scripts.");
bool registrationResult = false;
bool result = ExecuteWithLock(
[&]
{
auto pyUri = QString_To_Py_String(repoUri);
auto pythonRegistrationResult = m_register.attr("register")(
pybind11::none(), pybind11::none(), pybind11::none(), pybind11::none(), pybind11::none(), pybind11::none(), pyUri);
// Returns an exit code so boolify it then invert result
registrationResult = !pythonRegistrationResult.cast<bool>();
});
return result && registrationResult;
}
bool PythonBindings::RemoveGemRepo(const QString& repoUri)
{
bool registrationResult = false;
bool result = ExecuteWithLock(
[&]
{
auto pythonRegistrationResult = m_register.attr("register")(
pybind11::none(), // engine_path
pybind11::none(), // project_path
pybind11::none(), // gem_path
pybind11::none(), // external_subdir_path
pybind11::none(), // template_path
pybind11::none(), // restricted_path
QString_To_Py_String(repoUri), // repo_uri
pybind11::none(), // default_engines_folder
pybind11::none(), // default_projects_folder
pybind11::none(), // default_gems_folder
pybind11::none(), // default_templates_folder
pybind11::none(), // default_restricted_folder
pybind11::none(), // default_third_party_folder
pybind11::none(), // external_subdir_engine_path
pybind11::none(), // external_subdir_project_path
true, // remove
false // force
);
// Returns an exit code so boolify it then invert result
registrationResult = !pythonRegistrationResult.cast<bool>();
});
return result && registrationResult;
}
GemRepoInfo PythonBindings::GetGemRepoInfo(pybind11::handle repoUri)
{
GemRepoInfo gemRepoInfo;
gemRepoInfo.m_repoLink = Py_To_String(repoUri);
gemRepoInfo.m_repoUri = Py_To_String(repoUri);
auto data = m_manifest.attr("get_repo_json_data")(repoUri);
if (pybind11::isinstance<pybind11::dict>(data))
@ -957,7 +1000,7 @@ namespace O3DE::ProjectManager
try
{
// required
gemRepoInfo.m_repoLink = Py_To_String(data["repo_uri"]);
gemRepoInfo.m_repoUri = Py_To_String(data["repo_uri"]);
gemRepoInfo.m_name = Py_To_String(data["repo_name"]);
gemRepoInfo.m_creator = Py_To_String(data["origin"]);
@ -1019,13 +1062,13 @@ namespace O3DE::ProjectManager
#else
GemRepoInfo mockJohnRepo("JohnCreates", "John Smith", QDateTime(QDate(2021, 8, 31), QTime(11, 57)), true);
mockJohnRepo.m_summary = "John's Summary. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sollicitudin dapibus urna";
mockJohnRepo.m_repoLink = "https://github.com/o3de/o3de";
mockJohnRepo.m_repoUri = "https://github.com/o3de/o3de";
mockJohnRepo.m_additionalInfo = "John's additional info. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sollicitu.";
gemRepos.push_back(mockJohnRepo);
GemRepoInfo mockJaneRepo("JanesGems", "Jane Doe", QDateTime(QDate(2021, 9, 10), QTime(18, 23)), false);
mockJaneRepo.m_summary = "Jane's Summary.";
mockJaneRepo.m_repoLink = "https://github.com/o3de/o3de.org";
mockJaneRepo.m_repoUri = "https://github.com/o3de/o3de.org";
gemRepos.push_back(mockJaneRepo);
#endif // MOCK_GEM_REPO_INFO

@ -58,7 +58,8 @@ namespace O3DE::ProjectManager
AZ::Outcome<QVector<ProjectTemplateInfo>> GetProjectTemplates(const QString& projectPath = {}) override;
// Gem Repos
AZ::Outcome<void, AZStd::string> AddGemRepo(const QString& repoUri) override;
bool AddGemRepo(const QString& repoUri) override;
bool RemoveGemRepo(const QString& repoUri) override;
AZ::Outcome<QVector<GemRepoInfo>, AZStd::string> GetAllGemRepoInfos() override;
private:

@ -169,11 +169,18 @@ namespace O3DE::ProjectManager
// Gem Repos
/**
* A gem repo to engine. Registers this gem repo with the current engine.
* @param repoUri the absolute filesystem path or url to the gem repo manifest file.
* @return An outcome with the success flag as well as an error message in case of a failure.
* Registers this gem repo with the current engine.
* @param repoUri the absolute filesystem path or url to the gem repo.
* @return true on success, false on failure.
*/
virtual bool AddGemRepo(const QString& repoUri) = 0;
/**
* Unregisters this gem repo with the current engine.
* @param repoUri the absolute filesystem path or url to the gem repo.
* @return true on success, false on failure.
*/
virtual AZ::Outcome<void, AZStd::string> AddGemRepo(const QString& repoUri) = 0;
virtual bool RemoveGemRepo(const QString& repoUri) = 0;
/**
* Get all available gem repo infos. Gathers all repos registered with the engine.

@ -536,7 +536,8 @@ def get_repo_path(repo_uri: str, cache_folder: str = None) -> pathlib.Path:
if not cache_folder:
cache_folder = get_o3de_cache_folder()
repo_sha256 = hashlib.sha256(repo_uri.encode())
repo_manifest = f'{repo_uri}/repo.json'
repo_sha256 = hashlib.sha256(repo_manifest.encode())
return cache_folder / str(repo_sha256.hexdigest() + '.json')
def get_registered(engine_name: str = None,

@ -71,7 +71,7 @@ def process_add_o3de_repo(file_name: str or pathlib.Path,
# Having a repo is also optional
repo_list = []
try:
repo_list.add(repo_data['repos'])
repo_list.append(repo_data['repos'])
except KeyError:
pass

Loading…
Cancel
Save