diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qrc b/Code/Tools/ProjectManager/Resources/ProjectManager.qrc
index 33acfa9e1b..014a098a91 100644
--- a/Code/Tools/ProjectManager/Resources/ProjectManager.qrc
+++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qrc
@@ -31,5 +31,6 @@
CarrotArrowDown.svg
Summary.svg
WindowClose.svg
+ Warning.svg
diff --git a/Code/Tools/ProjectManager/Resources/Warning.svg b/Code/Tools/ProjectManager/Resources/Warning.svg
new file mode 100644
index 0000000000..28f7bc5f42
--- /dev/null
+++ b/Code/Tools/ProjectManager/Resources/Warning.svg
@@ -0,0 +1,5 @@
+
diff --git a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp
index 0e3a4ba95d..93f8895079 100644
--- a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp
+++ b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp
@@ -206,7 +206,11 @@ namespace O3DE::ProjectManager
PythonBindingsInterface::Get()->AddProject(projectInfo.m_path);
#ifdef TEMPLATE_GEM_CONFIGURATION_ENABLED
- m_gemCatalogScreen->EnableDisableGemsForProject(projectInfo.m_path);
+ if (!m_gemCatalogScreen->EnableDisableGemsForProject(projectInfo.m_path))
+ {
+ QMessageBox::critical(this, tr("Failed to configure gems"), tr("Failed to configure gems for template."));
+ return;
+ }
#endif // TEMPLATE_GEM_CONFIGURATION_ENABLED
projectInfo.m_needsBuild = true;
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp
index 2c92af4e51..763c9dfb75 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp
@@ -14,6 +14,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -144,12 +145,23 @@ namespace O3DE::ProjectManager
}
}
- void GemCatalogScreen::EnableDisableGemsForProject(const QString& projectPath)
+ bool GemCatalogScreen::EnableDisableGemsForProject(const QString& projectPath)
{
IPythonBindings* pythonBindings = PythonBindingsInterface::Get();
QVector toBeAdded = m_gemModel->GatherGemsToBeAdded();
QVector toBeRemoved = m_gemModel->GatherGemsToBeRemoved();
+ if (m_gemModel->DoGemsToBeAddedHaveRequirements())
+ {
+ GemRequirementDialog* confirmRequirementsDialog = new GemRequirementDialog(m_gemModel, toBeAdded, this);
+ confirmRequirementsDialog->exec();
+
+ if (confirmRequirementsDialog->GetButtonResult() != QDialogButtonBox::ApplyRole)
+ {
+ return false;
+ }
+ }
+
for (const QModelIndex& modelIndex : toBeAdded)
{
const QString gemPath = GemModel::GetPath(modelIndex);
@@ -158,6 +170,8 @@ namespace O3DE::ProjectManager
{
QMessageBox::critical(nullptr, "Operation failed",
QString("Cannot add gem %1 to project.\n\nError:\n%2").arg(GemModel::GetName(modelIndex), result.GetError().c_str()));
+
+ return false;
}
}
@@ -169,8 +183,12 @@ namespace O3DE::ProjectManager
{
QMessageBox::critical(nullptr, "Operation failed",
QString("Cannot remove gem %1 from project.\n\nError:\n%2").arg(GemModel::GetName(modelIndex), result.GetError().c_str()));
+
+ return false;
}
}
+
+ return true;
}
ProjectManagerScreen GemCatalogScreen::GetScreenEnum()
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h
index f5092e837a..fc771d9168 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h
@@ -33,7 +33,7 @@ namespace O3DE::ProjectManager
ProjectManagerScreen GetScreenEnum() override;
void ReinitForProject(const QString& projectPath, bool isNewProject);
- void EnableDisableGemsForProject(const QString& projectPath);
+ bool EnableDisableGemsForProject(const QString& projectPath);
private:
void FillModel(const QString& projectPath, bool isNewProject);
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h
index 722783ece1..f99e9689f3 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h
@@ -73,6 +73,7 @@ namespace O3DE::ProjectManager
Platforms m_platforms;
Types m_types; //! Asset and/or Code and/or Tool
QStringList m_features;
+ QString m_requirement;
QString m_directoryLink;
QString m_documentationLink;
QString m_version = "Unknown Version";
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp
index 3ecc18231e..119ec68d3a 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp
@@ -16,6 +16,7 @@
#include
#include
#include
+#include
namespace O3DE::ProjectManager
{
@@ -70,6 +71,22 @@ namespace O3DE::ProjectManager
m_directoryLinkLabel->SetUrl(m_model->GetDirectoryLink(modelIndex));
m_documentationLinkLabel->SetUrl(m_model->GetDocLink(modelIndex));
+ if (m_model->HasRequirement(modelIndex))
+ {
+ m_reqirementsIconLabel->show();
+ m_reqirementsTitleLabel->show();
+ m_reqirementsTextLabel->show();
+
+ m_reqirementsTitleLabel->setText("Requirement");
+ m_reqirementsTextLabel->setText(m_model->GetRequirement(modelIndex));
+ }
+ else
+ {
+ m_reqirementsIconLabel->hide();
+ m_reqirementsTitleLabel->hide();
+ m_reqirementsTextLabel->hide();
+ }
+
// Depending and conflicting gems
m_dependingGems->Update("Depending Gems", "The following Gems will be automatically enabled with this Gem.", m_model->GetDependingGemNames(modelIndex));
m_conflictingGems->Update("Conflicting Gems", "The following Gems will be automatically disabled with this Gem.", m_model->GetConflictingGemNames(modelIndex));
@@ -134,6 +151,28 @@ namespace O3DE::ProjectManager
m_mainLayout->addSpacing(10);
+ // Requirements
+ m_reqirementsTitleLabel = GemInspector::CreateStyledLabel(m_mainLayout, 16, s_headerColor);
+
+ QHBoxLayout* requrementsLayout = new QHBoxLayout();
+ requrementsLayout->setAlignment(Qt::AlignTop);
+ requrementsLayout->setMargin(0);
+ requrementsLayout->setSpacing(0);
+
+ m_reqirementsIconLabel = new QLabel();
+ m_reqirementsIconLabel->setPixmap(QIcon(":/Warning.svg").pixmap(24, 24));
+ requrementsLayout->addWidget(m_reqirementsIconLabel);
+
+ m_reqirementsTextLabel = GemInspector::CreateStyledLabel(requrementsLayout, 10, s_textColor);
+ m_reqirementsTextLabel->setWordWrap(true);
+
+ QSpacerItem* reqirementsSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding);
+ requrementsLayout->addSpacerItem(reqirementsSpacer);
+
+ m_mainLayout->addLayout(requrementsLayout);
+
+ m_mainLayout->addSpacing(20);
+
// Depending and conflicting gems
m_dependingGems = new GemsSubWidget();
m_mainLayout->addWidget(m_dependingGems);
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h
index 69c065c81e..4363ea3bc1 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h
@@ -76,6 +76,11 @@ namespace O3DE::ProjectManager
LinkLabel* m_directoryLinkLabel = nullptr;
LinkLabel* m_documentationLinkLabel = nullptr;
+ // Requirements
+ QLabel* m_reqirementsTitleLabel = nullptr;
+ QLabel* m_reqirementsIconLabel = nullptr;
+ QLabel* m_reqirementsTextLabel = nullptr;
+
// Depending and conflicting gems
GemsSubWidget* m_dependingGems = nullptr;
GemsSubWidget* m_conflictingGems = nullptr;
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp
index 03787de7e8..6529e4cf3d 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp
@@ -11,7 +11,7 @@
*/
#include
-#include "GemModel.h"
+#include
#include
#include
#include
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h
index 48f173ec3f..a155d9ece0 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h
@@ -62,7 +62,7 @@ namespace O3DE::ProjectManager
inline constexpr static int s_buttonCircleRadius = s_buttonBorderRadius - 2;
inline constexpr static qreal s_buttonFontSize = 10.0;
- private:
+ 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;
@@ -71,6 +71,7 @@ namespace O3DE::ProjectManager
QAbstractItemModel* m_model = nullptr;
+ private:
// Platform icons
void AddPlatformIcon(GemInfo::Platform platform, const QString& iconPath);
inline constexpr static int s_platformIconSize = 12;
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp
index 2838277696..575c09db05 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp
@@ -10,11 +10,9 @@
*
*/
-#include "GemListView.h"
-#include "GemItemDelegate.h"
+#include
+#include
#include
-#include
-#include
namespace O3DE::ProjectManager
{
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.h
index 178de2395f..5f1a018b9f 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.h
@@ -13,7 +13,6 @@
#pragma once
#if !defined(Q_MOC_RUN)
-#include "GemInfo.h"
#include
#include
#include
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp
index 5dc40723c9..7d9d86e3a7 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp
@@ -49,6 +49,7 @@ namespace O3DE::ProjectManager
item->setData(gemInfo.m_binarySizeInKB, RoleBinarySize);
item->setData(gemInfo.m_features, RoleFeatures);
item->setData(gemInfo.m_path, RolePath);
+ item->setData(gemInfo.m_requirement, RoleRequirement);
appendRow(item);
@@ -183,6 +184,11 @@ namespace O3DE::ProjectManager
return modelIndex.data(RolePath).toString();
}
+ QString GemModel::GetRequirement(const QModelIndex& modelIndex)
+ {
+ return modelIndex.data(RoleRequirement).toString();
+ }
+
bool GemModel::IsAdded(const QModelIndex& modelIndex)
{
return modelIndex.data(RoleIsAdded).toBool();
@@ -208,6 +214,24 @@ namespace O3DE::ProjectManager
return (modelIndex.data(RoleWasPreviouslyAdded).toBool() && !modelIndex.data(RoleIsAdded).toBool());
}
+ bool GemModel::HasRequirement(const QModelIndex& modelIndex)
+ {
+ return !modelIndex.data(RoleRequirement).toString().isEmpty();
+ }
+
+ bool GemModel::DoGemsToBeAddedHaveRequirements() const
+ {
+ for (int row = 0; row < rowCount(); ++row)
+ {
+ const QModelIndex modelIndex = index(row, 0);
+ if (NeedsToBeAdded(modelIndex) && HasRequirement(modelIndex))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
QVector GemModel::GatherGemsToBeAdded() const
{
QVector result;
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h
index 2e05472cdf..301053a9bf 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h
@@ -53,12 +53,16 @@ namespace O3DE::ProjectManager
static int GetBinarySizeInKB(const QModelIndex& modelIndex);
static QStringList GetFeatures(const QModelIndex& modelIndex);
static QString GetPath(const QModelIndex& modelIndex);
+ static QString GetRequirement(const QModelIndex& modelIndex);
static bool IsAdded(const QModelIndex& modelIndex);
static void SetIsAdded(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isAdded);
static void SetWasPreviouslyAdded(QAbstractItemModel& model, const QModelIndex& modelIndex, bool wasAdded);
static bool NeedsToBeAdded(const QModelIndex& modelIndex);
static bool NeedsToBeRemoved(const QModelIndex& modelIndex);
+ static bool HasRequirement(const QModelIndex& modelIndex);
+
+ bool DoGemsToBeAddedHaveRequirements() const;
QVector GatherGemsToBeAdded() const;
QVector GatherGemsToBeRemoved() const;
@@ -84,7 +88,8 @@ namespace O3DE::ProjectManager
RoleBinarySize,
RoleFeatures,
RoleTypes,
- RolePath
+ RolePath,
+ RoleRequirement
};
QHash m_nameToIndexMap;
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.cpp
new file mode 100644
index 0000000000..07024a799b
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.cpp
@@ -0,0 +1,93 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+
+#include
+#include
+
+#include
+
+namespace O3DE::ProjectManager
+{
+ GemRequirementDelegate::GemRequirementDelegate(QAbstractItemModel* model, QObject* parent)
+ : GemItemDelegate(model, parent)
+ {
+ }
+
+ void GemRequirementDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const
+ {
+ if (!modelIndex.isValid())
+ {
+ return;
+ }
+
+ QStyleOptionViewItem options(option);
+ initStyleOption(&options, modelIndex);
+
+ painter->save();
+ painter->setRenderHint(QPainter::Antialiasing);
+
+ QRect fullRect, itemRect, contentRect;
+ CalcRects(options, fullRect, itemRect, contentRect);
+
+ QFont standardFont(options.font);
+ standardFont.setPixelSize(s_fontSize);
+ QFontMetrics standardFontMetrics(standardFont);
+
+ painter->save();
+ painter->setClipping(true);
+ painter->setClipRect(fullRect);
+ painter->setFont(options.font);
+
+ // Draw background
+ painter->fillRect(fullRect, m_backgroundColor);
+
+ // Draw item background
+ const QColor itemBackgroundColor = m_itemBackgroundColor;
+ painter->fillRect(itemRect, itemBackgroundColor);
+
+ // Gem name
+ QString gemName = GemModel::GetName(modelIndex);
+ QFont gemNameFont(options.font);
+ const int firstColumnMaxTextWidth = s_summaryStartX - 30;
+ gemName = QFontMetrics(gemNameFont).elidedText(gemName, Qt::TextElideMode::ElideRight, firstColumnMaxTextWidth);
+ gemNameFont.setPixelSize(s_gemNameFontSize);
+ gemNameFont.setBold(true);
+ QRect gemNameRect = GetTextRect(gemNameFont, gemName, s_gemNameFontSize);
+ gemNameRect.moveTo(contentRect.left(), contentRect.center().y() - s_gemNameFontSize);
+
+ painter->setFont(gemNameFont);
+ painter->setPen(m_textColor);
+ painter->drawText(gemNameRect, Qt::TextSingleLine, gemName);
+
+ // Gem requirement
+ const QSize requirementSize = QSize(contentRect.width() - s_summaryStartX - s_itemMargins.right(), contentRect.height());
+ const QRect requirementRect = QRect(QPoint(contentRect.left() + s_summaryStartX, contentRect.top()), requirementSize);
+
+ painter->setFont(standardFont);
+ painter->setPen(m_textColor);
+
+ const QString requirement = GemModel::GetRequirement(modelIndex);
+ painter->drawText(requirementRect, Qt::AlignLeft | Qt::TextWordWrap, requirement);
+
+ painter->restore();
+ }
+
+ bool GemRequirementDelegate::editorEvent(
+ [[maybe_unused]] QEvent* event,
+ [[maybe_unused]] QAbstractItemModel* model,
+ [[maybe_unused]] const QStyleOptionViewItem& option,
+ [[maybe_unused]] const QModelIndex& modelIndex)
+ {
+ // Do nothing here
+ return false;
+ }
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.h
new file mode 100644
index 0000000000..b221dcb8fe
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.h
@@ -0,0 +1,37 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+
+#pragma once
+
+#if !defined(Q_MOC_RUN)
+#include
+#endif
+
+
+namespace O3DE::ProjectManager
+{
+ class GemRequirementDelegate
+ : public GemItemDelegate
+ {
+ Q_OBJECT // AUTOMOC
+
+ public:
+ explicit GemRequirementDelegate(QAbstractItemModel* model, QObject* parent = nullptr);
+ ~GemRequirementDelegate() = default;
+
+ void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const override;
+ bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) override;
+
+ const QColor m_backgroundColor = QColor("#444444"); // Outside of the actual gem item
+ const QColor m_itemBackgroundColor = QColor("#393939"); // Background color of the gem item
+ };
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.cpp
new file mode 100644
index 0000000000..ad0e64b1ca
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.cpp
@@ -0,0 +1,92 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace O3DE::ProjectManager
+{
+ GemRequirementDialog::GemRequirementDialog(GemModel* model, const QVector& gemsToAdd, QWidget* parent)
+ : QDialog(parent)
+ {
+ setWindowTitle(tr("Manual setup is required"));
+ setModal(true);
+
+ QVBoxLayout* vLayout = new QVBoxLayout();
+ vLayout->setMargin(0);
+ vLayout->setContentsMargins(25, 10, 25, 10);
+ vLayout->setSizeConstraint(QLayout::SetFixedSize);
+ setLayout(vLayout);
+
+ QHBoxLayout* instructionLayout = new QHBoxLayout();
+ instructionLayout->setMargin(0);
+
+ QLabel* instructionIconLabel = new QLabel();
+ instructionIconLabel->setPixmap(QIcon(":/Warning.svg").pixmap(32, 32));
+ instructionLayout->addWidget(instructionIconLabel);
+
+ instructionLayout->addSpacing(10);
+
+ QLabel* instructionLabel = new QLabel(tr("The following Gem(s) require manual setup before the project can be built successfully."));
+ instructionLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
+ instructionLayout->addWidget(instructionLabel);
+
+ QSpacerItem* instructionSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum);
+ instructionLayout->addSpacerItem(instructionSpacer);
+
+ vLayout->addLayout(instructionLayout);
+
+ vLayout->addSpacing(20);
+
+ GemRequirementFilterProxyModel* proxModel = new GemRequirementFilterProxyModel(model, gemsToAdd, this);
+
+ GemRequirementListView* m_gemListView = new GemRequirementListView(proxModel, proxModel->GetSelectionModel(), this);
+ vLayout->addWidget(m_gemListView);
+
+ QDialogButtonBox* dialogButtons = new QDialogButtonBox();
+ dialogButtons->setObjectName("footer");
+ vLayout->addWidget(dialogButtons);
+
+ QPushButton* cancelButton = dialogButtons->addButton(tr("Cancel"), QDialogButtonBox::RejectRole);
+ cancelButton->setProperty("secondary", true);
+ QPushButton* continueButton = dialogButtons->addButton(tr("Continue"), QDialogButtonBox::ApplyRole);
+
+ connect(cancelButton, &QPushButton::clicked, this, &GemRequirementDialog::CancelButtonPressed);
+ connect(continueButton, &QPushButton::clicked, this, &GemRequirementDialog::ContinueButtonPressed);
+ }
+
+ QDialogButtonBox::ButtonRole GemRequirementDialog::GetButtonResult()
+ {
+ return m_buttonResult;
+ }
+
+ void GemRequirementDialog::CancelButtonPressed()
+ {
+ m_buttonResult = QDialogButtonBox::RejectRole;
+ close();
+ }
+
+ void GemRequirementDialog::ContinueButtonPressed()
+ {
+ m_buttonResult = QDialogButtonBox::ApplyRole;
+ close();
+ }
+
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.h
new file mode 100644
index 0000000000..4295c5d586
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.h
@@ -0,0 +1,41 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#pragma once
+
+#if !defined(Q_MOC_RUN)
+#include
+
+#include
+#endif
+
+namespace O3DE::ProjectManager
+{
+ QT_FORWARD_DECLARE_CLASS(GemModel)
+
+ class GemRequirementDialog
+ : public QDialog
+ {
+ Q_OBJECT // AUTOMOC
+ public:
+ explicit GemRequirementDialog(GemModel* model, const QVector& gemsToAdd, QWidget *parent = nullptr);
+ ~GemRequirementDialog() = default;
+
+ QDialogButtonBox::ButtonRole GetButtonResult();
+
+ private:
+ void CancelButtonPressed();
+ void ContinueButtonPressed();
+
+ QDialogButtonBox::ButtonRole m_buttonResult = QDialogButtonBox::RejectRole;
+ };
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.cpp
new file mode 100644
index 0000000000..120ec63313
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.cpp
@@ -0,0 +1,51 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+
+#include
+#include
+
+#include
+
+namespace O3DE::ProjectManager
+{
+ GemRequirementFilterProxyModel::GemRequirementFilterProxyModel(GemModel* sourceModel, const QVector& addedGems, QObject* parent)
+ : QSortFilterProxyModel(parent)
+ , m_sourceModel(sourceModel)
+ , m_addedGems(addedGems)
+ {
+ setSourceModel(sourceModel);
+ m_selectionProxyModel = new AzQtComponents::SelectionProxyModel(sourceModel->GetSelectionModel(), this, parent);
+ }
+
+ bool GemRequirementFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const
+ {
+ // Do not use sourceParent->child because an invalid parent does not produce valid children (which our index function does)
+ QModelIndex sourceIndex = sourceModel()->index(sourceRow, 0, sourceParent);
+ if (!sourceIndex.isValid())
+ {
+ return false;
+ }
+
+ if (!m_addedGems.contains(sourceIndex))
+ {
+ return false;
+ }
+
+ if (!m_sourceModel->HasRequirement(sourceIndex))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.h
new file mode 100644
index 0000000000..a891d63d0c
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.h
@@ -0,0 +1,44 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+
+#pragma once
+
+#if !defined(Q_MOC_RUN)
+#include
+#include
+#endif
+
+QT_FORWARD_DECLARE_CLASS(QItemSelectionModel)
+
+namespace O3DE::ProjectManager
+{
+ QT_FORWARD_DECLARE_CLASS(GemModel)
+
+ class GemRequirementFilterProxyModel
+ : public QSortFilterProxyModel
+ {
+ Q_OBJECT // AUTOMOC
+
+ public:
+ GemRequirementFilterProxyModel(GemModel* sourceModel, const QVector& addedGems, QObject* parent = nullptr);
+
+ AzQtComponents::SelectionProxyModel* GetSelectionModel() const { return m_selectionProxyModel; }
+
+ bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override;
+
+ private:
+ GemModel* m_sourceModel = nullptr;
+ AzQtComponents::SelectionProxyModel* m_selectionProxyModel = nullptr;
+
+ QVector m_addedGems;
+ };
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementListView.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementListView.cpp
new file mode 100644
index 0000000000..a86ae876c2
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementListView.cpp
@@ -0,0 +1,30 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+
+#include
+#include
+#include
+
+namespace O3DE::ProjectManager
+{
+ GemRequirementListView::GemRequirementListView(QAbstractItemModel* model, QItemSelectionModel* selectionModel, QWidget* parent)
+ : QListView(parent)
+ {
+ setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
+
+ setStyleSheet("background-color: #444444;");
+
+ setModel(model);
+ setSelectionModel(selectionModel);
+ setItemDelegate(new GemRequirementDelegate(model, this));
+ }
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementListView.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementListView.h
new file mode 100644
index 0000000000..25b2837e30
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementListView.h
@@ -0,0 +1,32 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+
+#pragma once
+
+#if !defined(Q_MOC_RUN)
+#include
+#include
+#include
+#endif
+
+namespace O3DE::ProjectManager
+{
+ class GemRequirementListView
+ : public QListView
+ {
+ Q_OBJECT // AUTOMOC
+
+ public:
+ explicit GemRequirementListView(QAbstractItemModel* model, QItemSelectionModel* selectionModel, QWidget* parent = nullptr);
+ ~GemRequirementListView() = default;
+ };
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp
index 993c0abeaa..db376fb195 100644
--- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp
+++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp
@@ -661,6 +661,7 @@ namespace O3DE::ProjectManager
gemInfo.m_displayName = Py_To_String_Optional(data, "DisplayName", gemInfo.m_name);
gemInfo.m_summary = Py_To_String_Optional(data, "Summary", "");
gemInfo.m_version = Py_To_String_Optional(data, "Version", "");
+ gemInfo.m_requirement = Py_To_String_Optional(data, "Requirements", "");
if (data.contains("Tags"))
{
diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp
index f5414a67a1..e51d9e4996 100644
--- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp
+++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp
@@ -140,7 +140,11 @@ namespace O3DE::ProjectManager
else if (m_stack->currentIndex() == ScreenOrder::Gems && m_gemCatalogScreen)
{
// Enable or disable the gems that got adjusted in the gem catalog and apply them to the given project.
- m_gemCatalogScreen->EnableDisableGemsForProject(m_projectInfo.m_path);
+ if (!m_gemCatalogScreen->EnableDisableGemsForProject(m_projectInfo.m_path))
+ {
+ QMessageBox::critical(this, tr("Failed to configure gems"), tr("Failed to configure gems for project."));
+ return;
+ }
shouldRebuild = true;
}
diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake
index 8e4c4cd321..7eaeed0b96 100644
--- a/Code/Tools/ProjectManager/project_manager_files.cmake
+++ b/Code/Tools/ProjectManager/project_manager_files.cmake
@@ -87,6 +87,14 @@ set(FILES
Source/GemCatalog/GemListHeaderWidget.cpp
Source/GemCatalog/GemModel.h
Source/GemCatalog/GemModel.cpp
+ Source/GemCatalog/GemRequirementDialog.h
+ Source/GemCatalog/GemRequirementDialog.cpp
+ Source/GemCatalog/GemRequirementDelegate.h
+ Source/GemCatalog/GemRequirementDelegate.cpp
+ Source/GemCatalog/GemRequirementFilterProxyModel.h
+ Source/GemCatalog/GemRequirementFilterProxyModel.cpp
+ Source/GemCatalog/GemRequirementListView.h
+ Source/GemCatalog/GemRequirementListView.cpp
Source/GemCatalog/GemSortFilterProxyModel.h
Source/GemCatalog/GemSortFilterProxyModel.cpp
)