Merge branch 'development' into issues/exception_handling

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>
This commit is contained in:
Esteban Papp
2021-10-14 12:41:43 -07:00
222 changed files with 5742 additions and 1124 deletions
@@ -590,20 +590,22 @@ TEST_F(PlatformConfigurationUnitTests, Test_GemHandling)
AssetUtilities::ResetAssetRoot();
ASSERT_EQ(2, config.GetScanFolderCount());
ASSERT_EQ(4, config.GetScanFolderCount());
EXPECT_FALSE(config.GetScanFolderAt(0).IsRoot());
EXPECT_TRUE(config.GetScanFolderAt(0).RecurseSubFolders());
// the first one is a game gem, so its order should be above 1 but below 100.
EXPECT_GE(config.GetScanFolderAt(0).GetOrder(), 100);
EXPECT_EQ(0, config.GetScanFolderAt(0).ScanPath().compare(expectedScanFolder, Qt::CaseInsensitive));
// for each gem, there are currently 1 scan folder, the gem assets folder, with no output prefix
// for each gem, there are currently 2 scan folders:
// The Gem's 'Assets' folder
// The Gem's 'Registry' folder
expectedScanFolder = tempPath.absoluteFilePath("Gems/LmbrCentral/v2/Assets");
EXPECT_FALSE(config.GetScanFolderAt(1).IsRoot() );
EXPECT_TRUE(config.GetScanFolderAt(1).RecurseSubFolders());
EXPECT_GT(config.GetScanFolderAt(1).GetOrder(), config.GetScanFolderAt(0).GetOrder());
EXPECT_EQ(0, config.GetScanFolderAt(1).ScanPath().compare(expectedScanFolder, Qt::CaseInsensitive));
EXPECT_FALSE(config.GetScanFolderAt(2).IsRoot() );
EXPECT_TRUE(config.GetScanFolderAt(2).RecurseSubFolders());
EXPECT_GT(config.GetScanFolderAt(2).GetOrder(), config.GetScanFolderAt(0).GetOrder());
EXPECT_EQ(0, config.GetScanFolderAt(2).ScanPath().compare(expectedScanFolder, Qt::CaseInsensitive));
}
TEST_F(PlatformConfigurationUnitTests, Test_MetaFileTypes)
@@ -1582,6 +1582,24 @@ namespace AssetProcessor
gemOrder,
/*scanFolderId*/ 0,
/*canSaveNewAssets*/ true)); // Users can create assets like slices in Gem asset folders.
// Now add another scan folder on Gem/GemName/Registry...
gemFolder = gemDir.absoluteFilePath(AzFramework::GemInfo::GetGemRegistryFolder());
gemFolder = AssetUtilities::NormalizeDirectoryPath(gemFolder);
assetBrowserDisplayName = AzFramework::GemInfo::GetGemRegistryFolder();
portableKey = QString("gemregistry-%1").arg(gemNameAsUuid);
gemOrder++;
AZ_TracePrintf(AssetProcessor::DebugChannel, "Adding GEM registry folder for monitoring / scanning: %s.\n", gemFolder.toUtf8().data());
AddScanFolder(ScanFolderInfo(
gemFolder,
assetBrowserDisplayName,
portableKey,
isRoot,
isRecursive,
platforms,
gemOrder));
}
}
}
@@ -0,0 +1,3 @@
<svg width="16" height="11" viewBox="0 0 16 11" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.7872 2.91865C11.4965 1.25029 10.0476 0 8.31169 0C6.91408 0 5.66005 0.823481 5.09382 2.08042C5.05787 2.07875 5.02234 2.07792 4.98701 2.07792C3.81195 2.07792 2.7921 2.8241 2.42743 3.92062C0.986389 4.39377 0 5.73881 0 7.27273C0 9.22057 1.58462 10.8052 3.53247 10.8052H12.0519C14.229 10.8052 16 9.03418 16 6.85714C16 4.59242 14.085 2.75595 11.7872 2.91865ZM8.31169 9.35065L5.61039 6.44156H7.27273V4.57143H9.35065V6.44156H11.013L8.31169 9.35065Z" fill="#E4E8EB"/>
</svg>

After

Width:  |  Height:  |  Size: 575 B

@@ -34,9 +34,11 @@
<file>Warning.svg</file>
<file>Backgrounds/DefaultBackground.jpg</file>
<file>Backgrounds/FtueBackground.jpg</file>
<file>FeatureTagClose.svg</file>
<file>X.svg</file>
<file>Refresh.svg</file>
<file>Edit.svg</file>
<file>Delete.svg</file>
<file>Download.svg</file>
<file>in_progress.gif</file>
</qresource>
</RCC>

Before

Width:  |  Height:  |  Size: 400 B

After

Width:  |  Height:  |  Size: 400 B

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:64985a78205da45f4bb92b040c348d96fe7cd7277549c1f79c430469a0d3bab7
size 166393
@@ -33,7 +33,7 @@ namespace O3DE::ProjectManager
m_closeButton = new QPushButton();
m_closeButton->setFlat(true);
m_closeButton->setIcon(QIcon(":/FeatureTagClose.svg"));
m_closeButton->setIcon(QIcon(":/X.svg"));
m_closeButton->setIconSize(QSize(12, 12));
m_closeButton->setStyleSheet("QPushButton { background-color: transparent; border: 0px }");
layout->addWidget(m_closeButton);
@@ -8,6 +8,8 @@
#include "GemInfo.h"
#include <QObject>
namespace O3DE::ProjectManager
{
GemInfo::GemInfo(const QString& name, const QString& creator, const QString& summary, Platforms platforms, bool isAdded)
@@ -29,17 +31,17 @@ namespace O3DE::ProjectManager
switch (platform)
{
case Android:
return "Android";
return QObject::tr("Android");
case iOS:
return "iOS";
return QObject::tr("iOS");
case Linux:
return "Linux";
return QObject::tr("Linux");
case macOS:
return "macOS";
return QObject::tr("macOS");
case Windows:
return "Windows";
return QObject::tr("Windows");
default:
return "<Unknown Platform>";
return QObject::tr("<Unknown Platform>");
}
}
@@ -48,13 +50,13 @@ namespace O3DE::ProjectManager
switch (type)
{
case Asset:
return "Asset";
return QObject::tr("Asset");
case Code:
return "Code";
return QObject::tr("Code");
case Tool:
return "Tool";
return QObject::tr("Tool");
default:
return "<Unknown Type>";
return QObject::tr("<Unknown Type>");
}
}
@@ -62,15 +64,33 @@ namespace O3DE::ProjectManager
{
switch (origin)
{
case Open3DEEngine:
return "Open 3D Engine";
case Open3DEngine:
return QObject::tr("Open 3D Engine");
case Local:
return "Local";
return QObject::tr("Local");
case Remote:
return QObject::tr("Remote");
default:
return "<Unknown Gem Origin>";
return QObject::tr("<Unknown Gem Origin>");
}
}
QString GemInfo::GetDownloadStatusString(DownloadStatus status)
{
switch (status)
{
case NotDownloaded:
return QObject::tr("Not Downloaded");
case Downloading:
return QObject::tr("Downloading");
case Downloaded:
return QObject::tr("Downloaded");
case UnknownDownloadStatus:
default:
return QObject::tr("<Unknown Download Status>");
}
};
bool GemInfo::IsPlatformSupported(Platform platform) const
{
return (m_platforms & platform);
@@ -44,13 +44,23 @@ namespace O3DE::ProjectManager
enum GemOrigin
{
Open3DEEngine = 1 << 0,
Open3DEngine = 1 << 0,
Local = 1 << 1,
NumGemOrigins = 2
Remote = 1 << 2,
NumGemOrigins = 3
};
Q_DECLARE_FLAGS(GemOrigins, GemOrigin)
static QString GetGemOriginString(GemOrigin origin);
enum DownloadStatus
{
UnknownDownloadStatus = -1,
NotDownloaded,
Downloading,
Downloaded,
};
static QString GetDownloadStatusString(DownloadStatus status);
GemInfo() = default;
GemInfo(const QString& name, const QString& creator, const QString& summary, Platforms platforms, bool isAdded);
bool IsPlatformSupported(Platform platform) const;
@@ -68,6 +78,7 @@ namespace O3DE::ProjectManager
QString m_summary = "No summary provided.";
Platforms m_platforms;
Types m_types; //! Asset and/or Code and/or Tool
DownloadStatus m_downloadStatus = UnknownDownloadStatus;
QStringList m_features;
QString m_requirement;
QString m_directoryLink;
@@ -10,6 +10,7 @@
#include <GemCatalog/GemModel.h>
#include <GemCatalog/GemSortFilterProxyModel.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <QEvent>
#include <QAbstractItemView>
#include <QPainter>
@@ -20,6 +21,7 @@
#include <QTextDocument>
#include <QAbstractTextDocumentLayout>
#include <QDesktopServices>
#include <QMovie>
namespace O3DE::ProjectManager
{
@@ -32,6 +34,11 @@ namespace O3DE::ProjectManager
AddPlatformIcon(GemInfo::Linux, ":/Linux.svg");
AddPlatformIcon(GemInfo::macOS, ":/macOS.svg");
AddPlatformIcon(GemInfo::Windows, ":/Windows.svg");
SetStatusIcon(m_notDownloadedPixmap, ":/Download.svg");
SetStatusIcon(m_unknownStatusPixmap, ":/X.svg");
m_downloadingMovie = new QMovie(":/in_progress.gif");
}
void GemItemDelegate::AddPlatformIcon(GemInfo::Platform platform, const QString& iconPath)
@@ -41,6 +48,25 @@ namespace O3DE::ProjectManager
m_platformIcons.insert(platform, QIcon(iconPath).pixmap(static_cast<int>(static_cast<qreal>(s_platformIconSize) * aspectRatio), s_platformIconSize));
}
void GemItemDelegate::SetStatusIcon(QPixmap& m_iconPixmap, const QString& iconPath)
{
QPixmap pixmap(iconPath);
float aspectRatio = static_cast<float>(pixmap.width()) / pixmap.height();
int xScaler = s_statusIconSize;
int yScaler = s_statusIconSize;
if (aspectRatio > 1.0f)
{
yScaler = static_cast<int>(1.0f / aspectRatio * s_statusIconSize);
}
else if (aspectRatio < 1.0f)
{
xScaler = static_cast<int>(aspectRatio * s_statusIconSize);
}
m_iconPixmap = QPixmap(QIcon(iconPath).pixmap(xScaler, yScaler));
}
void GemItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const
{
if (!modelIndex.isValid())
@@ -56,6 +82,8 @@ namespace O3DE::ProjectManager
QRect fullRect, itemRect, contentRect;
CalcRects(options, fullRect, itemRect, contentRect);
QRect buttonRect = CalcButtonRect(contentRect);
QFont standardFont(options.font);
standardFont.setPixelSize(static_cast<int>(s_fontSize));
QFontMetrics standardFontMetrics(standardFont);
@@ -114,7 +142,8 @@ namespace O3DE::ProjectManager
const QRect summaryRect = CalcSummaryRect(contentRect, hasTags);
DrawText(summary, painter, summaryRect, standardFont);
DrawButton(painter, contentRect, modelIndex);
DrawDownloadStatusIcon(painter, contentRect, buttonRect, modelIndex);
DrawButton(painter, buttonRect, modelIndex);
DrawPlatformIcons(painter, contentRect, modelIndex);
DrawFeatureTags(painter, contentRect, featureTags, standardFont, summaryRect);
@@ -270,7 +299,7 @@ namespace O3DE::ProjectManager
QRect GemItemDelegate::CalcButtonRect(const QRect& contentRect) const
{
const QPoint topLeft = QPoint(contentRect.right() - s_buttonWidth - s_itemMargins.right(), contentRect.top() + contentRect.height() / 2 - s_buttonHeight / 2);
const QPoint topLeft = QPoint(contentRect.right() - s_buttonWidth, contentRect.center().y() - s_buttonHeight / 2);
const QSize size = QSize(s_buttonWidth, s_buttonHeight);
return QRect(topLeft, size);
}
@@ -378,10 +407,9 @@ namespace O3DE::ProjectManager
painter->restore();
}
void GemItemDelegate::DrawButton(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const
void GemItemDelegate::DrawButton(QPainter* painter, const QRect& buttonRect, const QModelIndex& modelIndex) const
{
painter->save();
const QRect buttonRect = CalcButtonRect(contentRect);
QPoint circleCenter;
if (GemModel::IsAdded(modelIndex))
@@ -427,4 +455,45 @@ namespace O3DE::ProjectManager
return QString();
}
void GemItemDelegate::DrawDownloadStatusIcon(QPainter* painter, const QRect& contentRect, const QRect& buttonRect, const QModelIndex& modelIndex) const
{
const GemInfo::DownloadStatus downloadStatus = GemModel::GetDownloadStatus(modelIndex);
// Show no icon if gem is already downloaded
if (downloadStatus == GemInfo::DownloadStatus::Downloaded)
{
return;
}
QPixmap currentFrame;
const QPixmap* statusPixmap;
if (downloadStatus == GemInfo::DownloadStatus::Downloading)
{
if (m_downloadingMovie->state() != QMovie::Running)
{
m_downloadingMovie->start();
emit MovieStartedPlaying(m_downloadingMovie);
}
currentFrame = m_downloadingMovie->currentPixmap();
currentFrame = currentFrame.scaled(s_statusIconSize, s_statusIconSize);
statusPixmap = &currentFrame;
}
else if (downloadStatus == GemInfo::DownloadStatus::NotDownloaded)
{
statusPixmap = &m_notDownloadedPixmap;
}
else
{
statusPixmap = &m_unknownStatusPixmap;
}
QSize statusSize = statusPixmap->size();
painter->drawPixmap(
buttonRect.left() - s_statusButtonSpacing - statusSize.width(),
contentRect.center().y() - statusSize.height() / 2,
*statusPixmap);
}
} // namespace O3DE::ProjectManager
@@ -49,13 +49,13 @@ namespace O3DE::ProjectManager
// Margin and borders
inline constexpr static QMargins s_itemMargins = QMargins(/*left=*/16, /*top=*/8, /*right=*/16, /*bottom=*/8); // Item border distances
inline constexpr static QMargins s_contentMargins = QMargins(/*left=*/20, /*top=*/12, /*right=*/15, /*bottom=*/12); // Distances of the elements within an item to the item borders
inline constexpr static QMargins s_contentMargins = QMargins(/*left=*/20, /*top=*/12, /*right=*/20, /*bottom=*/12); // Distances of the elements within an item to the item borders
inline constexpr static int s_borderWidth = 4;
// Button
inline constexpr static int s_buttonWidth = 55;
inline constexpr static int s_buttonHeight = 18;
inline constexpr static int s_buttonBorderRadius = 9;
inline constexpr static int s_buttonWidth = 32;
inline constexpr static int s_buttonHeight = 16;
inline constexpr static int s_buttonBorderRadius = s_buttonHeight / 2;
inline constexpr static int s_buttonCircleRadius = s_buttonBorderRadius - 2;
inline constexpr static qreal s_buttonFontSize = 10.0;
@@ -65,6 +65,9 @@ namespace O3DE::ProjectManager
inline constexpr static int s_featureTagBorderMarginY = 3;
inline constexpr static int s_featureTagSpacing = 7;
signals:
void MovieStartedPlaying(const QMovie* playingMovie) const;
protected:
bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) override;
bool helpEvent(QHelpEvent* event, QAbstractItemView* view, const QStyleOptionViewItem& option, const QModelIndex& index) override;
@@ -74,9 +77,10 @@ namespace O3DE::ProjectManager
QRect CalcButtonRect(const QRect& contentRect) const;
QRect CalcSummaryRect(const QRect& contentRect, bool hasTags) const;
void DrawPlatformIcons(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const;
void DrawButton(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const;
void DrawButton(QPainter* painter, const QRect& buttonRect, const QModelIndex& modelIndex) const;
void DrawFeatureTags(QPainter* painter, const QRect& contentRect, const QStringList& featureTags, const QFont& standardFont, const QRect& summaryRect) const;
void DrawText(const QString& text, QPainter* painter, const QRect& rect, const QFont& standardFont) const;
void DrawDownloadStatusIcon(QPainter* painter, const QRect& contentRect, const QRect& buttonRect, const QModelIndex& modelIndex) const;
QAbstractItemModel* m_model = nullptr;
@@ -85,5 +89,14 @@ namespace O3DE::ProjectManager
void AddPlatformIcon(GemInfo::Platform platform, const QString& iconPath);
inline constexpr static int s_platformIconSize = 12;
QHash<GemInfo::Platform, QPixmap> m_platformIcons;
// Status icons
void SetStatusIcon(QPixmap& m_iconPixmap, const QString& iconPath);
inline constexpr static int s_statusIconSize = 16;
inline constexpr static int s_statusButtonSpacing = 5;
QPixmap m_unknownStatusPixmap;
QPixmap m_notDownloadedPixmap;
QMovie* m_downloadingMovie = nullptr;
};
} // namespace O3DE::ProjectManager
@@ -103,11 +103,11 @@ namespace O3DE::ProjectManager
QSpacerItem* horizontalSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum);
columnHeaderLayout->addSpacerItem(horizontalSpacer);
QLabel* gemSelectedLabel = new QLabel(tr("Selected"));
QLabel* gemSelectedLabel = new QLabel(tr("Status"));
gemSelectedLabel->setObjectName("GemCatalogHeaderLabel");
columnHeaderLayout->addWidget(gemSelectedLabel);
columnHeaderLayout->addSpacing(65);
columnHeaderLayout->addSpacing(72);
vLayout->addLayout(columnHeaderLayout);
}
@@ -9,6 +9,8 @@
#include <GemCatalog/GemListView.h>
#include <GemCatalog/GemItemDelegate.h>
#include <QMovie>
namespace O3DE::ProjectManager
{
GemListView::GemListView(QAbstractItemModel* model, QItemSelectionModel* selectionModel, QWidget* parent)
@@ -19,6 +21,17 @@ namespace O3DE::ProjectManager
setModel(model);
setSelectionModel(selectionModel);
setItemDelegate(new GemItemDelegate(model, this));
GemItemDelegate* itemDelegate = new GemItemDelegate(model, this);
connect(itemDelegate, &GemItemDelegate::MovieStartedPlaying, [=](const QMovie* playingMovie)
{
// Force redraw when movie is playing so animation is smooth
connect(playingMovie, &QMovie::frameChanged, this, [=]
{
this->viewport()->repaint();
});
});
setItemDelegate(itemDelegate);
}
} // namespace O3DE::ProjectManager
@@ -48,6 +48,7 @@ namespace O3DE::ProjectManager
item->setData(gemInfo.m_features, RoleFeatures);
item->setData(gemInfo.m_path, RolePath);
item->setData(gemInfo.m_requirement, RoleRequirement);
item->setData(gemInfo.m_downloadStatus, RoleDownloadStatus);
appendRow(item);
@@ -132,6 +133,11 @@ namespace O3DE::ProjectManager
return static_cast<GemInfo::Types>(modelIndex.data(RoleTypes).toInt());
}
GemInfo::DownloadStatus GemModel::GetDownloadStatus(const QModelIndex& modelIndex)
{
return static_cast<GemInfo::DownloadStatus>(modelIndex.data(RoleDownloadStatus).toInt());
}
QString GemModel::GetSummary(const QModelIndex& modelIndex)
{
return modelIndex.data(RoleSummary).toString();
@@ -373,6 +379,11 @@ namespace O3DE::ProjectManager
return previouslyAdded && !added;
}
void GemModel::SetDownloadStatus(QAbstractItemModel& model, const QModelIndex& modelIndex, GemInfo::DownloadStatus status)
{
model.setData(modelIndex, status, RoleDownloadStatus);
}
bool GemModel::HasRequirement(const QModelIndex& modelIndex)
{
return !modelIndex.data(RoleRequirement).toString().isEmpty();
@@ -40,6 +40,7 @@ namespace O3DE::ProjectManager
static GemInfo::GemOrigin GetGemOrigin(const QModelIndex& modelIndex);
static GemInfo::Platforms GetPlatforms(const QModelIndex& modelIndex);
static GemInfo::Types GetTypes(const QModelIndex& modelIndex);
static GemInfo::DownloadStatus GetDownloadStatus(const QModelIndex& modelIndex);
static QString GetSummary(const QModelIndex& modelIndex);
static QString GetDirectoryLink(const QModelIndex& modelIndex);
static QString GetDocLink(const QModelIndex& modelIndex);
@@ -64,6 +65,7 @@ namespace O3DE::ProjectManager
static bool NeedsToBeRemoved(const QModelIndex& modelIndex, bool includeDependencies = false);
static bool HasRequirement(const QModelIndex& modelIndex);
static void UpdateDependencies(QAbstractItemModel& model, const QModelIndex& modelIndex);
static void SetDownloadStatus(QAbstractItemModel& model, const QModelIndex& modelIndex, GemInfo::DownloadStatus status);
bool DoGemsToBeAddedHaveRequirements() const;
bool HasDependentGemsToRemove() const;
@@ -101,7 +103,8 @@ namespace O3DE::ProjectManager
RoleFeatures,
RoleTypes,
RolePath,
RoleRequirement
RoleRequirement,
RoleDownloadStatus
};
QHash<QString, QModelIndex> m_nameToIndexMap;
@@ -668,7 +668,21 @@ namespace O3DE::ProjectManager
if (gemInfo.m_creator.contains("Open 3D Engine"))
{
gemInfo.m_gemOrigin = GemInfo::GemOrigin::Open3DEEngine;
gemInfo.m_gemOrigin = GemInfo::GemOrigin::Open3DEngine;
}
else if (gemInfo.m_creator.contains("Amazon Web Services"))
{
gemInfo.m_gemOrigin = GemInfo::GemOrigin::Local;
}
else if (data.contains("origin"))
{
gemInfo.m_gemOrigin = GemInfo::GemOrigin::Remote;
}
// As long Base Open3DEngine gems are installed before first startup non-remote gems will be downloaded
if (gemInfo.m_gemOrigin != GemInfo::GemOrigin::Remote)
{
gemInfo.m_downloadStatus = GemInfo::DownloadStatus::Downloaded;
}
if (data.contains("user_tags"))