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>
This commit is contained in:
@@ -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 AZ::Outcome<void, AZStd::string> AddGemRepo(const QString& repoUri) = 0;
|
||||
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 bool RemoveGemRepo(const QString& repoUri) = 0;
|
||||
|
||||
/**
|
||||
* Get all available gem repo infos. Gathers all repos registered with the engine.
|
||||
|
||||
Reference in New Issue
Block a user