Merge stabilization/2110 as of 20edb35cdc into development (#5319)

This commit is contained in:
Chris Burel
2021-11-08 15:22:17 -08:00
committed by GitHub
256 changed files with 3492 additions and 1166 deletions
@@ -30,7 +30,7 @@ namespace O3DE::ProjectManager
: ScreenWidget(parent)
{
m_gemModel = new GemModel(this);
m_proxModel = new GemSortFilterProxyModel(m_gemModel, this);
m_proxyModel = new GemSortFilterProxyModel(m_gemModel, this);
QVBoxLayout* vLayout = new QVBoxLayout();
vLayout->setMargin(0);
@@ -39,7 +39,7 @@ namespace O3DE::ProjectManager
m_downloadController = new DownloadController();
m_headerWidget = new GemCatalogHeaderWidget(m_gemModel, m_proxModel, m_downloadController);
m_headerWidget = new GemCatalogHeaderWidget(m_gemModel, m_proxyModel, m_downloadController);
vLayout->addWidget(m_headerWidget);
connect(m_gemModel, &GemModel::gemStatusChanged, this, &GemCatalogScreen::OnGemStatusChanged);
@@ -50,10 +50,12 @@ namespace O3DE::ProjectManager
hLayout->setMargin(0);
vLayout->addLayout(hLayout);
m_gemListView = new GemListView(m_proxModel, m_proxModel->GetSelectionModel(), this);
m_gemListView = new GemListView(m_proxyModel, m_proxyModel->GetSelectionModel(), this);
m_gemInspector = new GemInspector(m_gemModel, this);
m_gemInspector->setFixedWidth(240);
connect(m_gemInspector, &GemInspector::TagClicked, this, &GemCatalogScreen::SelectGem);
QWidget* filterWidget = new QWidget(this);
filterWidget->setFixedWidth(240);
m_filterWidgetLayout = new QVBoxLayout();
@@ -61,7 +63,7 @@ namespace O3DE::ProjectManager
m_filterWidgetLayout->setSpacing(0);
filterWidget->setLayout(m_filterWidgetLayout);
GemListHeaderWidget* listHeaderWidget = new GemListHeaderWidget(m_proxModel);
GemListHeaderWidget* listHeaderWidget = new GemListHeaderWidget(m_proxyModel);
QVBoxLayout* middleVLayout = new QVBoxLayout();
middleVLayout->setMargin(0);
@@ -84,15 +86,17 @@ namespace O3DE::ProjectManager
m_gemsToRegisterWithProject.clear();
FillModel(projectPath);
m_proxyModel->ResetFilters();
if (m_filterWidget)
{
m_filterWidget->hide();
m_filterWidget->deleteLater();
m_filterWidget->ResetAllFilters();
}
else
{
m_filterWidget = new GemFilterWidget(m_proxyModel);
m_filterWidgetLayout->addWidget(m_filterWidget);
}
m_proxModel->ResetFilters();
m_filterWidget = new GemFilterWidget(m_proxModel);
m_filterWidgetLayout->addWidget(m_filterWidget);
m_headerWidget->ReinitForProject();
@@ -192,6 +196,20 @@ namespace O3DE::ProjectManager
}
}
void GemCatalogScreen::SelectGem(const QString& gemName)
{
QModelIndex modelIndex = m_gemModel->FindIndexByNameString(gemName);
if (!m_proxyModel->filterAcceptsRow(modelIndex.row(), QModelIndex()))
{
m_proxyModel->ResetFilters();
m_filterWidget->ResetAllFilters();
}
QModelIndex proxyIndex = m_proxyModel->mapFromSource(modelIndex);
m_proxyModel->GetSelectionModel()->select(proxyIndex, QItemSelectionModel::ClearAndSelect);
m_gemListView->scrollTo(proxyIndex);
}
void GemCatalogScreen::hideEvent(QHideEvent* event)
{
ScreenWidget::hideEvent(event);
@@ -48,6 +48,7 @@ namespace O3DE::ProjectManager
public slots:
void OnGemStatusChanged(const QString& gemName, uint32_t numChangedDependencies);
void OnAddGemClicked();
void SelectGem(const QString& gemName);
protected:
void hideEvent(QHideEvent* event) override;
@@ -68,7 +69,7 @@ namespace O3DE::ProjectManager
GemInspector* m_gemInspector = nullptr;
GemModel* m_gemModel = nullptr;
GemCatalogHeaderWidget* m_headerWidget = nullptr;
GemSortFilterProxyModel* m_proxModel = nullptr;
GemSortFilterProxyModel* m_proxyModel = nullptr;
QVBoxLayout* m_filterWidgetLayout = nullptr;
GemFilterWidget* m_filterWidget = nullptr;
DownloadController* m_downloadController = nullptr;
@@ -213,11 +213,99 @@ namespace O3DE::ProjectManager
m_filterLayout->setContentsMargins(0, 0, 0, 0);
filterSection->setLayout(m_filterLayout);
ResetAllFilters();
}
void GemFilterWidget::ResetAllFilters()
{
ResetGemStatusFilter();
AddGemOriginFilter();
AddTypeFilter();
AddPlatformFilter();
AddFeatureFilter();
ResetGemOriginFilter();
ResetTypeFilter();
ResetPlatformFilter();
ResetFeatureFilter();
}
void GemFilterWidget::ResetFilterWidget(
FilterCategoryWidget*& filterPtr,
const QString& filterName,
const QVector<QString>& elementNames,
const QVector<int>& elementCounts,
int defaultShowCount)
{
bool wasCollapsed = false;
if (filterPtr)
{
wasCollapsed = filterPtr->IsCollapsed();
}
FilterCategoryWidget* filterWidget = new FilterCategoryWidget(
filterName, elementNames, elementCounts, /*showAllLessButton=*/defaultShowCount != 4, /*collapsed*/ wasCollapsed,
/*defaultShowCount=*/defaultShowCount);
if (filterPtr)
{
m_filterLayout->replaceWidget(filterPtr, filterWidget);
}
else
{
m_filterLayout->addWidget(filterWidget);
}
filterPtr->deleteLater();
filterPtr = filterWidget;
}
template<typename filterType, typename filterFlagsType>
void GemFilterWidget::ResetSimpleOrFilter(
FilterCategoryWidget*& filterPtr,
const QString& filterName,
int numFilterElements,
bool (*filterMatcher)(GemModel*, filterType, int),
QString (*typeStringGetter)(filterType),
filterFlagsType (GemSortFilterProxyModel::*filterFlagsGetter)() const,
void (GemSortFilterProxyModel::*filterFlagsSetter)(const filterFlagsType&))
{
QVector<QString> elementNames;
QVector<int> elementCounts;
const int numGems = m_gemModel->rowCount();
for (int filterIndex = 0; filterIndex < numFilterElements; ++filterIndex)
{
const filterType gemFilterToBeCounted = static_cast<filterType>(1 << filterIndex);
int gemFilterCount = 0;
for (int gemIndex = 0; gemIndex < numGems; ++gemIndex)
{
// If filter matches increment filter count
gemFilterCount += filterMatcher(m_gemModel, gemFilterToBeCounted, gemIndex);
}
elementNames.push_back(typeStringGetter(gemFilterToBeCounted));
elementCounts.push_back(gemFilterCount);
}
// Replace existing filter and delete old one
ResetFilterWidget(filterPtr, filterName, elementNames, elementCounts);
const QList<QAbstractButton*> buttons = filterPtr->GetButtonGroup()->buttons();
for (int i = 0; i < buttons.size(); ++i)
{
const filterType gemFilter = static_cast<filterType>(1 << i);
QAbstractButton* button = buttons[i];
connect(
button, &QAbstractButton::toggled, this,
[=](bool checked)
{
filterFlagsType gemFilters = (m_filterProxyModel->*filterFlagsGetter)();
if (checked)
{
gemFilters |= gemFilter;
}
else
{
gemFilters &= ~gemFilter;
}
(m_filterProxyModel->*filterFlagsSetter)(gemFilters);
});
}
}
void GemFilterWidget::ResetGemStatusFilter()
@@ -241,25 +329,7 @@ namespace O3DE::ProjectManager
elementNames.push_back(GemSortFilterProxyModel::GetGemActiveString(GemSortFilterProxyModel::GemActive::Inactive));
elementCounts.push_back(totalGems - enabledGemTotal);
bool wasCollapsed = false;
if (m_statusFilter)
{
wasCollapsed = m_statusFilter->IsCollapsed();
}
FilterCategoryWidget* filterWidget =
new FilterCategoryWidget("Status", elementNames, elementCounts, /*showAllLessButton=*/false, /*collapsed*/wasCollapsed);
if (m_statusFilter)
{
m_filterLayout->replaceWidget(m_statusFilter, filterWidget);
}
else
{
m_filterLayout->addWidget(filterWidget);
}
m_statusFilter->deleteLater();
m_statusFilter = filterWidget;
ResetFilterWidget(m_statusFilter, "Status", elementNames, elementCounts);
const QList<QAbstractButton*> buttons = m_statusFilter->GetButtonGroup()->buttons();
@@ -317,157 +387,42 @@ namespace O3DE::ProjectManager
connect(activeButton, &QAbstractButton::toggled, this, updateGemActive);
}
void GemFilterWidget::AddGemOriginFilter()
void GemFilterWidget::ResetGemOriginFilter()
{
QVector<QString> elementNames;
QVector<int> elementCounts;
const int numGems = m_gemModel->rowCount();
for (int originIndex = 0; originIndex < GemInfo::NumGemOrigins; ++originIndex)
{
const GemInfo::GemOrigin gemOriginToBeCounted = static_cast<GemInfo::GemOrigin>(1 << originIndex);
int gemOriginCount = 0;
for (int gemIndex = 0; gemIndex < numGems; ++gemIndex)
ResetSimpleOrFilter<GemInfo::GemOrigin, GemInfo::GemOrigins>
(
m_originFilter, "Provider", GemInfo::NumGemOrigins,
[](GemModel* gemModel, GemInfo::GemOrigin origin, int gemIndex)
{
const GemInfo::GemOrigin gemOrigin = m_gemModel->GetGemOrigin(m_gemModel->index(gemIndex, 0));
// Is the gem of the given origin?
if (gemOriginToBeCounted == gemOrigin)
{
gemOriginCount++;
}
}
elementNames.push_back(GemInfo::GetGemOriginString(gemOriginToBeCounted));
elementCounts.push_back(gemOriginCount);
}
FilterCategoryWidget* filterWidget = new FilterCategoryWidget("Provider", elementNames, elementCounts, /*showAllLessButton=*/false);
m_filterLayout->addWidget(filterWidget);
const QList<QAbstractButton*> buttons = filterWidget->GetButtonGroup()->buttons();
for (int i = 0; i < buttons.size(); ++i)
{
const GemInfo::GemOrigin gemOrigin = static_cast<GemInfo::GemOrigin>(1 << i);
QAbstractButton* button = buttons[i];
connect(button, &QAbstractButton::toggled, this, [=](bool checked)
{
GemInfo::GemOrigins gemOrigins = m_filterProxyModel->GetGemOrigins();
if (checked)
{
gemOrigins |= gemOrigin;
}
else
{
gemOrigins &= ~gemOrigin;
}
m_filterProxyModel->SetGemOrigins(gemOrigins);
});
}
return origin == gemModel->GetGemOrigin(gemModel->index(gemIndex, 0));
},
&GemInfo::GetGemOriginString, &GemSortFilterProxyModel::GetGemOrigins, &GemSortFilterProxyModel::SetGemOrigins
);
}
void GemFilterWidget::AddTypeFilter()
void GemFilterWidget::ResetTypeFilter()
{
QVector<QString> elementNames;
QVector<int> elementCounts;
const int numGems = m_gemModel->rowCount();
for (int typeIndex = 0; typeIndex < GemInfo::NumTypes; ++typeIndex)
{
const GemInfo::Type type = static_cast<GemInfo::Type>(1 << typeIndex);
int typeGemCount = 0;
for (int gemIndex = 0; gemIndex < numGems; ++gemIndex)
ResetSimpleOrFilter<GemInfo::Type, GemInfo::Types>(
m_typeFilter, "Type", GemInfo::NumTypes,
[](GemModel* gemModel, GemInfo::Type type, int gemIndex)
{
const GemInfo::Types types = m_gemModel->GetTypes(m_gemModel->index(gemIndex, 0));
// Is type (Asset, Code, Tool) part of the gem?
if (types & type)
{
typeGemCount++;
}
}
elementNames.push_back(GemInfo::GetTypeString(type));
elementCounts.push_back(typeGemCount);
}
FilterCategoryWidget* filterWidget = new FilterCategoryWidget("Type", elementNames, elementCounts, /*showAllLessButton=*/false);
m_filterLayout->addWidget(filterWidget);
const QList<QAbstractButton*> buttons = filterWidget->GetButtonGroup()->buttons();
for (int i = 0; i < buttons.size(); ++i)
{
const GemInfo::Type type = static_cast<GemInfo::Type>(1 << i);
QAbstractButton* button = buttons[i];
connect(button, &QAbstractButton::toggled, this, [=](bool checked)
{
GemInfo::Types types = m_filterProxyModel->GetTypes();
if (checked)
{
types |= type;
}
else
{
types &= ~type;
}
m_filterProxyModel->SetTypes(types);
});
}
return static_cast<bool>(type & gemModel->GetTypes(gemModel->index(gemIndex, 0)));
},
&GemInfo::GetTypeString, &GemSortFilterProxyModel::GetTypes, &GemSortFilterProxyModel::SetTypes);
}
void GemFilterWidget::AddPlatformFilter()
void GemFilterWidget::ResetPlatformFilter()
{
QVector<QString> elementNames;
QVector<int> elementCounts;
const int numGems = m_gemModel->rowCount();
for (int platformIndex = 0; platformIndex < GemInfo::NumPlatforms; ++platformIndex)
{
const GemInfo::Platform platform = static_cast<GemInfo::Platform>(1 << platformIndex);
int platformGemCount = 0;
for (int gemIndex = 0; gemIndex < numGems; ++gemIndex)
ResetSimpleOrFilter<GemInfo::Platform, GemInfo::Platforms>(
m_platformFilter, "Supported Platforms", GemInfo::NumPlatforms,
[](GemModel* gemModel, GemInfo::Platform platform, int gemIndex)
{
const GemInfo::Platforms platforms = m_gemModel->GetPlatforms(m_gemModel->index(gemIndex, 0));
// Is platform supported?
if (platforms & platform)
{
platformGemCount++;
}
}
elementNames.push_back(GemInfo::GetPlatformString(platform));
elementCounts.push_back(platformGemCount);
}
FilterCategoryWidget* filterWidget = new FilterCategoryWidget("Supported Platforms", elementNames, elementCounts, /*showAllLessButton=*/false);
m_filterLayout->addWidget(filterWidget);
const QList<QAbstractButton*> buttons = filterWidget->GetButtonGroup()->buttons();
for (int i = 0; i < buttons.size(); ++i)
{
const GemInfo::Platform platform = static_cast<GemInfo::Platform>(1 << i);
QAbstractButton* button = buttons[i];
connect(button, &QAbstractButton::toggled, this, [=](bool checked)
{
GemInfo::Platforms platforms = m_filterProxyModel->GetPlatforms();
if (checked)
{
platforms |= platform;
}
else
{
platforms &= ~platform;
}
m_filterProxyModel->SetPlatforms(platforms);
});
}
return static_cast<bool>(platform & gemModel->GetPlatforms(gemModel->index(gemIndex, 0)));
},
&GemInfo::GetPlatformString, &GemSortFilterProxyModel::GetPlatforms, &GemSortFilterProxyModel::SetPlatforms);
}
void GemFilterWidget::AddFeatureFilter()
void GemFilterWidget::ResetFeatureFilter()
{
// Alphabetically sorted, unique features and their number of occurrences in the gem database.
QMap<QString, int> uniqueFeatureCounts;
@@ -497,11 +452,15 @@ namespace O3DE::ProjectManager
elementCounts.push_back(iterator.value());
}
FilterCategoryWidget* filterWidget = new FilterCategoryWidget("Features", elementNames, elementCounts,
/*showAllLessButton=*/true, false, /*defaultShowCount=*/5);
m_filterLayout->addWidget(filterWidget);
ResetFilterWidget(m_featureFilter, "Features", elementNames, elementCounts, /*defaultShowCount=*/5);
const QList<QAbstractButton*> buttons = filterWidget->GetButtonGroup()->buttons();
for (QMetaObject::Connection& connection : m_featureTagConnections)
{
disconnect(connection);
}
m_featureTagConnections.clear();
const QList<QAbstractButton*> buttons = m_featureFilter->GetButtonGroup()->buttons();
for (int i = 0; i < buttons.size(); ++i)
{
const QString& feature = elementNames[i];
@@ -523,13 +482,13 @@ namespace O3DE::ProjectManager
});
// Sync the UI state with the proxy model filtering.
connect(m_filterProxyModel, &GemSortFilterProxyModel::OnInvalidated, this, [=]
m_featureTagConnections.push_back(connect(m_filterProxyModel, &GemSortFilterProxyModel::OnInvalidated, this, [=]
{
const QSet<QString>& filteredFeatureTags = m_filterProxyModel->GetFeatures();
const bool isChecked = filteredFeatureTags.contains(button->text());
QSignalBlocker signalsBlocker(button);
button->setChecked(isChecked);
});
}));
}
}
} // namespace O3DE::ProjectManager
@@ -66,17 +66,41 @@ namespace O3DE::ProjectManager
~GemFilterWidget() = default;
public slots:
void ResetAllFilters();
void ResetGemStatusFilter();
private:
void AddGemOriginFilter();
void AddTypeFilter();
void AddPlatformFilter();
void AddFeatureFilter();
void ResetGemOriginFilter();
void ResetTypeFilter();
void ResetPlatformFilter();
void ResetFeatureFilter();
void ResetFilterWidget(
FilterCategoryWidget*& filterPtr,
const QString& filterName,
const QVector<QString>& elementNames,
const QVector<int>& elementCounts,
int defaultShowCount = 4);
template<typename filterType, typename filterFlagsType>
void ResetSimpleOrFilter(
FilterCategoryWidget*& filterPtr,
const QString& filterName,
int numFilterElements,
bool (*filterMatcher)(GemModel*, filterType, int),
QString (*typeStringGetter)(filterType),
filterFlagsType (GemSortFilterProxyModel::*filterFlagsGetter)() const,
void (GemSortFilterProxyModel::*filterFlagsSetter)(const filterFlagsType&));
QVBoxLayout* m_filterLayout = nullptr;
GemModel* m_gemModel = nullptr;
GemSortFilterProxyModel* m_filterProxyModel = nullptr;
FilterCategoryWidget* m_statusFilter = nullptr;
FilterCategoryWidget* m_originFilter = nullptr;
FilterCategoryWidget* m_typeFilter = nullptr;
FilterCategoryWidget* m_platformFilter = nullptr;
FilterCategoryWidget* m_featureFilter = nullptr;
QVector<QMetaObject::Connection> m_featureTagConnections;
};
} // namespace O3DE::ProjectManager
@@ -81,6 +81,8 @@ namespace O3DE::ProjectManager
DownloadStatus m_downloadStatus = UnknownDownloadStatus;
QStringList m_features;
QString m_requirement;
QString m_licenseText;
QString m_licenseLink;
QString m_directoryLink;
QString m_documentationLink;
QString m_version = "Unknown Version";
@@ -52,6 +52,22 @@ namespace O3DE::ProjectManager
Update(selectedIndices[0]);
}
void SetLabelElidedText(QLabel* label, QString text)
{
QFontMetrics nameFontMetrics(label->font());
int labelWidth = label->width();
// Don't elide if the widgets are sized too small (sometimes occurs when loading gem catalog)
if (labelWidth > 100)
{
label->setText(nameFontMetrics.elidedText(text, Qt::ElideRight, labelWidth));
}
else
{
label->setText(text);
}
}
void GemInspector::Update(const QModelIndex& modelIndex)
{
if (!modelIndex.isValid())
@@ -59,38 +75,52 @@ namespace O3DE::ProjectManager
m_mainWidget->hide();
}
m_nameLabel->setText(m_model->GetDisplayName(modelIndex));
m_creatorLabel->setText(m_model->GetCreator(modelIndex));
SetLabelElidedText(m_nameLabel, m_model->GetDisplayName(modelIndex));
SetLabelElidedText(m_creatorLabel, m_model->GetCreator(modelIndex));
m_summaryLabel->setText(m_model->GetSummary(modelIndex));
m_summaryLabel->adjustSize();
m_licenseLinkLabel->setText(m_model->GetLicenseText(modelIndex));
m_licenseLinkLabel->SetUrl(m_model->GetLicenseLink(modelIndex));
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_requirementsIconLabel->show();
m_requirementsTitleLabel->show();
m_requirementsTextLabel->show();
m_requirementsMainSpacer->changeSize(0, 20, QSizePolicy::Fixed, QSizePolicy::Fixed);
m_reqirementsTitleLabel->setText("Requirement");
m_reqirementsTextLabel->setText(m_model->GetRequirement(modelIndex));
m_requirementsTitleLabel->setText(tr("Requirement"));
m_requirementsTextLabel->setText(m_model->GetRequirement(modelIndex));
}
else
{
m_reqirementsIconLabel->hide();
m_reqirementsTitleLabel->hide();
m_reqirementsTextLabel->hide();
m_requirementsIconLabel->hide();
m_requirementsTitleLabel->hide();
m_requirementsTextLabel->hide();
m_requirementsMainSpacer->changeSize(0, 0, QSizePolicy::Fixed, QSizePolicy::Fixed);
}
// Depending gems
m_dependingGems->Update("Depending Gems", "The following Gems will be automatically enabled with this Gem.", m_model->GetDependingGemNames(modelIndex));
QStringList dependingGems = m_model->GetDependingGemNames(modelIndex);
if (!dependingGems.isEmpty())
{
m_dependingGems->Update(tr("Depending Gems"), tr("The following Gems will be automatically enabled with this Gem."), dependingGems);
m_dependingGems->show();
}
else
{
m_dependingGems->hide();
}
// Additional information
m_versionLabel->setText(QString("Gem Version: %1").arg(m_model->GetVersion(modelIndex)));
m_lastUpdatedLabel->setText(QString("Last Updated: %1").arg(m_model->GetLastUpdated(modelIndex)));
m_binarySizeLabel->setText(QString("Binary Size: %1 KB").arg(m_model->GetBinarySizeInKB(modelIndex)));
m_versionLabel->setText(tr("Gem Version: %1").arg(m_model->GetVersion(modelIndex)));
m_lastUpdatedLabel->setText(tr("Last Updated: %1").arg(m_model->GetLastUpdated(modelIndex)));
m_binarySizeLabel->setText(tr("Binary Size: %1 KB").arg(m_model->GetBinarySizeInKB(modelIndex)));
m_mainWidget->adjustSize();
m_mainWidget->show();
@@ -108,35 +138,51 @@ namespace O3DE::ProjectManager
{
// Gem name, creator and summary
m_nameLabel = CreateStyledLabel(m_mainLayout, 18, s_headerColor);
m_creatorLabel = CreateStyledLabel(m_mainLayout, 12, s_headerColor);
m_creatorLabel = CreateStyledLabel(m_mainLayout, s_baseFontSize, s_headerColor);
m_mainLayout->addSpacing(5);
// TODO: QLabel seems to have issues determining the right sizeHint() for our font with the given font size.
// This results into squeezed elements in the layout in case the text is a little longer than a sentence.
m_summaryLabel = CreateStyledLabel(m_mainLayout, 12, s_textColor);
m_summaryLabel = CreateStyledLabel(m_mainLayout, s_baseFontSize, s_headerColor);
m_mainLayout->addWidget(m_summaryLabel);
m_summaryLabel->setWordWrap(true);
m_summaryLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
m_summaryLabel->setOpenExternalLinks(true);
m_mainLayout->addSpacing(5);
// License
{
QHBoxLayout* licenseHLayout = new QHBoxLayout();
licenseHLayout->setMargin(0);
licenseHLayout->setAlignment(Qt::AlignLeft);
m_mainLayout->addLayout(licenseHLayout);
QLabel* licenseLabel = CreateStyledLabel(licenseHLayout, s_baseFontSize, s_headerColor);
licenseLabel->setText(tr("License: "));
m_licenseLinkLabel = new LinkLabel("", QUrl(), s_baseFontSize);
licenseHLayout->addWidget(m_licenseLinkLabel);
licenseHLayout->addStretch();
m_mainLayout->addSpacing(5);
}
// Directory and documentation links
{
QHBoxLayout* linksHLayout = new QHBoxLayout();
linksHLayout->setMargin(0);
m_mainLayout->addLayout(linksHLayout);
QSpacerItem* spacerLeft = new QSpacerItem(0, 0, QSizePolicy::Expanding);
linksHLayout->addSpacerItem(spacerLeft);
linksHLayout->addStretch();
m_directoryLinkLabel = new LinkLabel("View in Directory");
m_directoryLinkLabel = new LinkLabel(tr("View in Directory"));
linksHLayout->addWidget(m_directoryLinkLabel);
linksHLayout->addWidget(new QLabel("|"));
m_documentationLinkLabel = new LinkLabel("Read Documentation");
m_documentationLinkLabel = new LinkLabel(tr("Read Documentation"));
linksHLayout->addWidget(m_documentationLinkLabel);
QSpacerItem* spacerRight = new QSpacerItem(0, 0, QSizePolicy::Expanding);
linksHLayout->addSpacerItem(spacerRight);
linksHLayout->addStretch();
m_mainLayout->addSpacing(8);
}
@@ -144,46 +190,48 @@ namespace O3DE::ProjectManager
// Separating line
QFrame* hLine = new QFrame();
hLine->setFrameShape(QFrame::HLine);
hLine->setStyleSheet("color: #666666;");
hLine->setObjectName("horizontalSeparatingLine");
m_mainLayout->addWidget(hLine);
m_mainLayout->addSpacing(10);
// Requirements
m_reqirementsTitleLabel = GemInspector::CreateStyledLabel(m_mainLayout, 16, s_headerColor);
m_requirementsTitleLabel = GemInspector::CreateStyledLabel(m_mainLayout, 16, s_headerColor);
QHBoxLayout* requrementsLayout = new QHBoxLayout();
requrementsLayout->setAlignment(Qt::AlignTop);
requrementsLayout->setMargin(0);
requrementsLayout->setSpacing(0);
QHBoxLayout* requirementsLayout = new QHBoxLayout();
requirementsLayout->setAlignment(Qt::AlignTop);
requirementsLayout->setMargin(0);
requirementsLayout->setSpacing(0);
m_reqirementsIconLabel = new QLabel();
m_reqirementsIconLabel->setPixmap(QIcon(":/Warning.svg").pixmap(24, 24));
requrementsLayout->addWidget(m_reqirementsIconLabel);
m_requirementsIconLabel = new QLabel();
m_requirementsIconLabel->setPixmap(QIcon(":/Warning.svg").pixmap(24, 24));
requirementsLayout->addWidget(m_requirementsIconLabel);
m_reqirementsTextLabel = GemInspector::CreateStyledLabel(requrementsLayout, 10, s_textColor);
m_reqirementsTextLabel->setWordWrap(true);
m_reqirementsTextLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
m_reqirementsTextLabel->setOpenExternalLinks(true);
m_requirementsTextLabel = GemInspector::CreateStyledLabel(requirementsLayout, 10, s_textColor);
m_requirementsTextLabel->setWordWrap(true);
m_requirementsTextLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
m_requirementsTextLabel->setOpenExternalLinks(true);
QSpacerItem* reqirementsSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding);
requrementsLayout->addSpacerItem(reqirementsSpacer);
QSpacerItem* requirementsSpacer = new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding);
requirementsLayout->addSpacerItem(requirementsSpacer);
m_mainLayout->addLayout(requrementsLayout);
m_mainLayout->addLayout(requirementsLayout);
m_mainLayout->addSpacing(20);
m_requirementsMainSpacer = new QSpacerItem(0, 20, QSizePolicy::Fixed, QSizePolicy::Fixed);
m_mainLayout->addSpacerItem(m_requirementsMainSpacer);
// Depending gems
m_dependingGems = new GemsSubWidget();
connect(m_dependingGems, &GemsSubWidget::TagClicked, this, [=](const QString& tag){ emit TagClicked(tag); });
m_mainLayout->addWidget(m_dependingGems);
m_mainLayout->addSpacing(20);
// Additional information
QLabel* additionalInfoLabel = CreateStyledLabel(m_mainLayout, 14, s_headerColor);
additionalInfoLabel->setText("Additional Information");
additionalInfoLabel->setText(tr("Additional Information"));
m_versionLabel = CreateStyledLabel(m_mainLayout, 12, s_textColor);
m_lastUpdatedLabel = CreateStyledLabel(m_mainLayout, 12, s_textColor);
m_binarySizeLabel = CreateStyledLabel(m_mainLayout, 12, s_textColor);
m_versionLabel = CreateStyledLabel(m_mainLayout, s_baseFontSize, s_textColor);
m_lastUpdatedLabel = CreateStyledLabel(m_mainLayout, s_baseFontSize, s_textColor);
m_binarySizeLabel = CreateStyledLabel(m_mainLayout, s_baseFontSize, s_textColor);
}
} // namespace O3DE::ProjectManager
@@ -16,7 +16,7 @@
#include <QItemSelection>
#include <QScrollArea>
#include <QWidget>
#include <QSpacerItem>
#endif
QT_FORWARD_DECLARE_CLASS(QVBoxLayout)
@@ -36,10 +36,16 @@ namespace O3DE::ProjectManager
void Update(const QModelIndex& modelIndex);
static QLabel* CreateStyledLabel(QLayout* layout, int fontSize, const QString& colorCodeString);
// Fonts
inline constexpr static int s_baseFontSize = 12;
// Colors
inline constexpr static const char* s_headerColor = "#FFFFFF";
inline constexpr static const char* s_textColor = "#DDDDDD";
signals:
void TagClicked(const QString& tag);
private slots:
void OnSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
@@ -54,13 +60,15 @@ namespace O3DE::ProjectManager
QLabel* m_nameLabel = nullptr;
QLabel* m_creatorLabel = nullptr;
QLabel* m_summaryLabel = nullptr;
LinkLabel* m_licenseLinkLabel = nullptr;
LinkLabel* m_directoryLinkLabel = nullptr;
LinkLabel* m_documentationLinkLabel = nullptr;
// Requirements
QLabel* m_reqirementsTitleLabel = nullptr;
QLabel* m_reqirementsIconLabel = nullptr;
QLabel* m_reqirementsTextLabel = nullptr;
QLabel* m_requirementsTitleLabel = nullptr;
QLabel* m_requirementsIconLabel = nullptr;
QLabel* m_requirementsTextLabel = nullptr;
QSpacerItem* m_requirementsMainSpacer = nullptr;
// Depending and conflicting gems
GemsSubWidget* m_dependingGems = nullptr;
@@ -58,10 +58,13 @@ namespace O3DE::ProjectManager
item->setData(gemInfo.m_path, RolePath);
item->setData(gemInfo.m_requirement, RoleRequirement);
item->setData(gemInfo.m_downloadStatus, RoleDownloadStatus);
item->setData(gemInfo.m_licenseText, RoleLicenseText);
item->setData(gemInfo.m_licenseLink, RoleLicenseLink);
appendRow(item);
const QModelIndex modelIndex = index(rowCount()-1, 0);
m_nameToIndexMap[gemInfo.m_displayName] = modelIndex;
m_nameToIndexMap[gemInfo.m_name] = modelIndex;
}
@@ -247,6 +250,16 @@ namespace O3DE::ProjectManager
return modelIndex.data(RoleRequirement).toString();
}
QString GemModel::GetLicenseText(const QModelIndex& modelIndex)
{
return modelIndex.data(RoleLicenseText).toString();
}
QString GemModel::GetLicenseLink(const QModelIndex& modelIndex)
{
return modelIndex.data(RoleLicenseLink).toString();
}
GemModel* GemModel::GetSourceModel(QAbstractItemModel* model)
{
GemSortFilterProxyModel* proxyModel = qobject_cast<GemSortFilterProxyModel*>(model);
@@ -50,6 +50,8 @@ namespace O3DE::ProjectManager
static QStringList GetFeatures(const QModelIndex& modelIndex);
static QString GetPath(const QModelIndex& modelIndex);
static QString GetRequirement(const QModelIndex& modelIndex);
static QString GetLicenseText(const QModelIndex& modelIndex);
static QString GetLicenseLink(const QModelIndex& modelIndex);
static GemModel* GetSourceModel(QAbstractItemModel* model);
static const GemModel* GetSourceModel(const QAbstractItemModel* model);
@@ -107,7 +109,9 @@ namespace O3DE::ProjectManager
RoleTypes,
RolePath,
RoleRequirement,
RoleDownloadStatus
RoleDownloadStatus,
RoleLicenseText,
RoleLicenseLink
};
QHash<QString, QModelIndex> m_nameToIndexMap;
@@ -207,6 +207,8 @@ namespace O3DE::ProjectManager
void GemSortFilterProxyModel::ResetFilters()
{
m_searchString.clear();
m_gemSelectedFilter = GemSelected::NoFilter;
m_gemActiveFilter = GemActive::NoFilter;
m_gemOriginFilter = {};
m_platformFilter = {};
m_typeFilter = {};
@@ -99,7 +99,7 @@ namespace O3DE::ProjectManager
m_nameLabel->setObjectName("gemRepoInspectorNameLabel");
m_mainLayout->addWidget(m_nameLabel);
m_repoLinkLabel = new LinkLabel(tr("Repo Url"), QUrl(""), 12, this);
m_repoLinkLabel = new LinkLabel(tr("Repo Url"), QUrl(), 12, this);
m_mainLayout->addWidget(m_repoLinkLabel);
m_mainLayout->addSpacing(5);
@@ -33,6 +33,7 @@ namespace O3DE::ProjectManager
m_layout->addWidget(m_textLabel);
m_tagWidget = new TagContainerWidget();
connect(m_tagWidget, &TagContainerWidget::TagClicked, this, [=](const QString& tag){ emit TagClicked(tag); });
m_layout->addWidget(m_tagWidget);
}
@@ -22,10 +22,15 @@ namespace O3DE::ProjectManager
class GemsSubWidget
: public QWidget
{
Q_OBJECT // AUTOMOC
public:
GemsSubWidget(QWidget* parent = nullptr);
void Update(const QString& title, const QString& text, const QStringList& gemNames);
signals:
void TagClicked(const QString& tag);
private:
QLabel* m_titleLabel = nullptr;
QLabel* m_textLabel = nullptr;
@@ -709,6 +709,8 @@ namespace O3DE::ProjectManager
gemInfo.m_requirement = Py_To_String_Optional(data, "requirements", "");
gemInfo.m_creator = Py_To_String_Optional(data, "origin", "");
gemInfo.m_documentationLink = Py_To_String_Optional(data, "documentation_url", "");
gemInfo.m_licenseText = Py_To_String_Optional(data, "license", "Unspecified License");
gemInfo.m_licenseLink = Py_To_String_Optional(data, "license_url", "");
if (gemInfo.m_creator.contains("Open 3D Engine"))
{
@@ -18,6 +18,11 @@ namespace O3DE::ProjectManager
setObjectName("TagWidget");
}
void TagWidget::mousePressEvent([[maybe_unused]] QMouseEvent* event)
{
emit(TagClicked(text()));
}
TagContainerWidget::TagContainerWidget(QWidget* parent)
: QWidget(parent)
{
@@ -45,7 +50,9 @@ namespace O3DE::ProjectManager
foreach (const QString& tag, tags)
{
flowLayout->addWidget(new TagWidget(tag));
TagWidget* tagWidget = new TagWidget(tag);
connect(tagWidget, &TagWidget::TagClicked, this, [=](const QString& tag){ emit TagClicked(tag); });
flowLayout->addWidget(tagWidget);
}
}
} // namespace O3DE::ProjectManager
@@ -25,6 +25,12 @@ namespace O3DE::ProjectManager
public:
explicit TagWidget(const QString& text, QWidget* parent = nullptr);
~TagWidget() = default;
signals:
void TagClicked(const QString& tag);
protected:
void mousePressEvent(QMouseEvent* event) override;
};
// Widget containing multiple tags, automatically wrapping based on the size
@@ -38,5 +44,8 @@ namespace O3DE::ProjectManager
~TagContainerWidget() = default;
void Update(const QStringList& tags);
signals:
void TagClicked(const QString& tag);
};
} // namespace O3DE::ProjectManager