Merge branch 'development' into Prism/ShowRepoGems

monroegm-disable-blank-issue-2
nggieber 4 years ago
commit 06f893edf1

@ -108,7 +108,7 @@ namespace O3DE::ProjectManager
// Draw refresh button // Draw refresh button
painter->drawPixmap( painter->drawPixmap(
repoUpdatedDateRect.left() + repoUpdatedDateRect.width() + s_refreshIconSpacing, repoUpdatedDateRect.left() + s_updatedMaxWidth + s_refreshIconSpacing,
contentRect.center().y() - s_refreshIconSize / 3, // Dividing size by 3 centers much better contentRect.center().y() - s_refreshIconSize / 3, // Dividing size by 3 centers much better
m_refreshIcon); m_refreshIcon);
@ -150,6 +150,11 @@ namespace O3DE::ProjectManager
emit RemoveRepo(modelIndex); emit RemoveRepo(modelIndex);
return true; return true;
} }
else if (keyEvent->key() == Qt::Key_R || keyEvent->key() == Qt::Key_F5)
{
emit RefreshRepo(modelIndex);
return true;
}
} }
if (event->type() == QEvent::MouseButtonPress) if (event->type() == QEvent::MouseButtonPress)
@ -160,6 +165,7 @@ namespace O3DE::ProjectManager
CalcRects(option, fullRect, itemRect, contentRect); CalcRects(option, fullRect, itemRect, contentRect);
const QRect buttonRect = CalcButtonRect(contentRect); const QRect buttonRect = CalcButtonRect(contentRect);
const QRect deleteButtonRect = CalcDeleteButtonRect(contentRect); const QRect deleteButtonRect = CalcDeleteButtonRect(contentRect);
const QRect refreshButtonRect = CalcRefreshButtonRect(contentRect, buttonRect);
if (buttonRect.contains(mouseEvent->pos())) if (buttonRect.contains(mouseEvent->pos()))
{ {
@ -172,6 +178,11 @@ namespace O3DE::ProjectManager
emit RemoveRepo(modelIndex); emit RemoveRepo(modelIndex);
return true; return true;
} }
else if (refreshButtonRect.contains(mouseEvent->pos()))
{
emit RefreshRepo(modelIndex);
return true;
}
} }
return QStyledItemDelegate::editorEvent(event, model, option, modelIndex); return QStyledItemDelegate::editorEvent(event, model, option, modelIndex);
@ -231,6 +242,13 @@ namespace O3DE::ProjectManager
return QRect(topLeft, QSize(s_iconSize, s_iconSize)); return QRect(topLeft, QSize(s_iconSize, s_iconSize));
} }
QRect GemRepoItemDelegate::CalcRefreshButtonRect(const QRect& contentRect, const QRect& buttonRect) const
{
const int topLeftX = buttonRect.left() + s_buttonWidth + s_buttonSpacing + s_nameMaxWidth + s_creatorMaxWidth + s_updatedMaxWidth + s_contentSpacing * 2 + s_refreshIconSpacing;
const QPoint topLeft = QPoint(topLeftX, contentRect.center().y() - s_refreshIconSize / 3);
return QRect(topLeft, QSize(s_refreshIconSize, s_refreshIconSize));
}
void GemRepoItemDelegate::DrawEditButtons(QPainter* painter, const QRect& contentRect) const void GemRepoItemDelegate::DrawEditButtons(QPainter* painter, const QRect& contentRect) const
{ {
painter->drawPixmap(contentRect.right() - s_iconSize, contentRect.center().y() - s_iconSize / 2, m_deleteIcon); painter->drawPixmap(contentRect.right() - s_iconSize, contentRect.center().y() - s_iconSize / 2, m_deleteIcon);

@ -68,12 +68,14 @@ namespace O3DE::ProjectManager
signals: signals:
void RemoveRepo(const QModelIndex& modelIndex); void RemoveRepo(const QModelIndex& modelIndex);
void RefreshRepo(const QModelIndex& modelIndex);
protected: protected:
void CalcRects(const QStyleOptionViewItem& option, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const; void CalcRects(const QStyleOptionViewItem& option, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const;
QRect GetTextRect(QFont& font, const QString& text, qreal fontSize) const; QRect GetTextRect(QFont& font, const QString& text, qreal fontSize) const;
QRect CalcButtonRect(const QRect& contentRect) const; QRect CalcButtonRect(const QRect& contentRect) const;
QRect CalcDeleteButtonRect(const QRect& contentRect) const; QRect CalcDeleteButtonRect(const QRect& contentRect) const;
QRect CalcRefreshButtonRect(const QRect& contentRect, const QRect& buttonRect) const;
void DrawButton(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const; void DrawButton(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const;
void DrawEditButtons(QPainter* painter, const QRect& contentRect) const; void DrawEditButtons(QPainter* painter, const QRect& contentRect) const;

@ -24,6 +24,7 @@ namespace O3DE::ProjectManager
GemRepoItemDelegate* itemDelegate = new GemRepoItemDelegate(model, this); GemRepoItemDelegate* itemDelegate = new GemRepoItemDelegate(model, this);
connect(itemDelegate, &GemRepoItemDelegate::RemoveRepo, this, &GemRepoListView::RemoveRepo); connect(itemDelegate, &GemRepoItemDelegate::RemoveRepo, this, &GemRepoListView::RemoveRepo);
connect(itemDelegate, &GemRepoItemDelegate::RefreshRepo, this, &GemRepoListView::RefreshRepo);
setItemDelegate(itemDelegate); setItemDelegate(itemDelegate);
} }
} // namespace O3DE::ProjectManager } // namespace O3DE::ProjectManager

@ -28,5 +28,6 @@ namespace O3DE::ProjectManager
signals: signals:
void RemoveRepo(const QModelIndex& modelIndex); void RemoveRepo(const QModelIndex& modelIndex);
void RefreshRepo(const QModelIndex& modelIndex);
}; };
} // namespace O3DE::ProjectManager } // namespace O3DE::ProjectManager

@ -126,6 +126,36 @@ namespace O3DE::ProjectManager
} }
} }
void GemRepoScreen::HandleRefreshAllButton()
{
bool refreshResult = PythonBindingsInterface::Get()->RefreshAllGemRepos();
Reinit();
if (!refreshResult)
{
QMessageBox::critical(
this, tr("Operation failed"), QString("Some repos failed to refresh."));
}
}
void GemRepoScreen::HandleRefreshRepoButton(const QModelIndex& modelIndex)
{
const QString repoUri = m_gemRepoModel->GetRepoUri(modelIndex);
AZ::Outcome<void, AZStd::string> refreshResult = PythonBindingsInterface::Get()->RefreshGemRepo(repoUri);
if (refreshResult.IsSuccess())
{
Reinit();
}
else
{
QMessageBox::critical(
this, tr("Operation failed"),
QString("Failed to refresh gem repo %1<br>Error:<br>%2")
.arg(m_gemRepoModel->GetName(modelIndex), refreshResult.GetError().c_str()));
}
}
void GemRepoScreen::FillModel() void GemRepoScreen::FillModel()
{ {
AZ::Outcome<QVector<GemRepoInfo>, AZStd::string> allGemRepoInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoInfos(); AZ::Outcome<QVector<GemRepoInfo>, AZStd::string> allGemRepoInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoInfos();
@ -237,6 +267,8 @@ namespace O3DE::ProjectManager
m_AllUpdateButton->setObjectName("gemRepoHeaderRefreshButton"); m_AllUpdateButton->setObjectName("gemRepoHeaderRefreshButton");
topMiddleHLayout->addWidget(m_AllUpdateButton); topMiddleHLayout->addWidget(m_AllUpdateButton);
connect(m_AllUpdateButton, &QPushButton::clicked, this, &GemRepoScreen::HandleRefreshAllButton);
topMiddleHLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum)); topMiddleHLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum));
QPushButton* addRepoButton = new QPushButton(tr("Add Repository"), this); QPushButton* addRepoButton = new QPushButton(tr("Add Repository"), this);
@ -280,6 +312,7 @@ namespace O3DE::ProjectManager
middleVLayout->addWidget(m_gemRepoListView); middleVLayout->addWidget(m_gemRepoListView);
connect(m_gemRepoListView, &GemRepoListView::RemoveRepo, this, &GemRepoScreen::HandleRemoveRepoButton); connect(m_gemRepoListView, &GemRepoListView::RemoveRepo, this, &GemRepoScreen::HandleRemoveRepoButton);
connect(m_gemRepoListView, &GemRepoListView::RefreshRepo, this, &GemRepoScreen::HandleRefreshRepoButton);
hLayout->addLayout(middleVLayout); hLayout->addLayout(middleVLayout);

@ -40,6 +40,8 @@ namespace O3DE::ProjectManager
public slots: public slots:
void HandleAddRepoButton(); void HandleAddRepoButton();
void HandleRemoveRepoButton(const QModelIndex& modelIndex); void HandleRemoveRepoButton(const QModelIndex& modelIndex);
void HandleRefreshAllButton();
void HandleRefreshRepoButton(const QModelIndex& modelIndex);
private: private:
void FillModel(); void FillModel();

@ -983,6 +983,46 @@ namespace O3DE::ProjectManager
} }
} }
AZ::Outcome<void, AZStd::string> PythonBindings::RefreshGemRepo(const QString& repoUri)
{
bool refreshResult = false;
AZ::Outcome<void, AZStd::string> result = ExecuteWithLockErrorHandling(
[&]
{
auto pyUri = QString_To_Py_String(repoUri);
auto pythonRefreshResult = m_repo.attr("refresh_repo")(pyUri);
// Returns an exit code so boolify it then invert result
refreshResult = !pythonRefreshResult.cast<bool>();
});
if (!result.IsSuccess())
{
return result;
}
else if (!refreshResult)
{
return AZ::Failure<AZStd::string>("Failed to refresh repo.");
}
return AZ::Success();
}
bool PythonBindings::RefreshAllGemRepos()
{
bool refreshResult = false;
bool result = ExecuteWithLock(
[&]
{
auto pythonRefreshResult = m_repo.attr("refresh_repos")();
// Returns an exit code so boolify it then invert result
refreshResult = !pythonRefreshResult.cast<bool>();
});
return result && refreshResult;
}
bool PythonBindings::AddGemRepo(const QString& repoUri) bool PythonBindings::AddGemRepo(const QString& repoUri)
{ {
bool registrationResult = false; bool registrationResult = false;

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

@ -176,6 +176,19 @@ namespace O3DE::ProjectManager
// Gem Repos // Gem Repos
/**
* Refresh gem repo in the current engine.
* @param repoUri the absolute filesystem path or url to the gem repo.
* @return An outcome with the success flag as well as an error message in case of a failure.
*/
virtual AZ::Outcome<void, AZStd::string> RefreshGemRepo(const QString& repoUri) = 0;
/**
* Refresh all gem repos in the current engine.
* @return true on success, false on failure.
*/
virtual bool RefreshAllGemRepos() = 0;
/** /**
* Registers this gem repo with the current engine. * Registers this gem repo with the current engine.
* @param repoUri the absolute filesystem path or url to the gem repo. * @param repoUri the absolute filesystem path or url to the gem repo.

@ -1,5 +1,5 @@
{ {
"Source" : "NewDepthOfFieldComposite", "Source" : "NewDepthOfFieldComposite.azsl",
"DepthStencilState" : "DepthStencilState" :
{ {

@ -1,5 +1,5 @@
{ {
"Source" : "NewDepthOfFieldDownsample", "Source" : "NewDepthOfFieldDownsample.azsl",
"DepthStencilState" : { "DepthStencilState" : {
"Depth" : { "Enable" : false } "Depth" : { "Enable" : false }

@ -1,5 +1,5 @@
{ {
"Source" : "NewDepthOfFieldFilterLarge", "Source" : "NewDepthOfFieldFilterLarge.azsl",
"DepthStencilState" : { "DepthStencilState" : {
"Depth" : { "Enable" : false } "Depth" : { "Enable" : false }

@ -1,5 +1,5 @@
{ {
"Source" : "NewDepthOfFieldFilterSmall", "Source" : "NewDepthOfFieldFilterSmall.azsl",
"DepthStencilState" : { "DepthStencilState" : {
"Depth" : { "Enable" : false } "Depth" : { "Enable" : false }

@ -1,5 +1,5 @@
{ {
"Source" : "NewDepthOfFieldTile3x3", "Source" : "NewDepthOfFieldTile3x3.azsl",
"DepthStencilState" : { "DepthStencilState" : {
"Depth" : { "Enable" : false } "Depth" : { "Enable" : false }

@ -1,5 +1,5 @@
{ {
"Source" : "NewDepthOfFieldTileReduce", "Source" : "NewDepthOfFieldTileReduce.azsl",
"ProgramSettings" : "ProgramSettings" :
{ {

@ -13,7 +13,7 @@ import shutil
import urllib.parse import urllib.parse
import urllib.request import urllib.request
import hashlib import hashlib
from datetime import datetime
from o3de import manifest, utils, validation from o3de import manifest, utils, validation
logger = logging.getLogger() logger = logging.getLogger()
@ -27,6 +27,7 @@ def process_add_o3de_repo(file_name: str or pathlib.Path,
return 1 return 1
cache_folder = manifest.get_o3de_cache_folder() cache_folder = manifest.get_o3de_cache_folder()
repo_data = {}
with file_name.open('r') as f: with file_name.open('r') as f:
try: try:
repo_data = json.load(f) repo_data = json.load(f)
@ -34,61 +35,72 @@ def process_add_o3de_repo(file_name: str or pathlib.Path,
logger.error(f'{file_name} failed to load: {str(e)}') logger.error(f'{file_name} failed to load: {str(e)}')
return 1 return 1
# A repo may not contain all types of object. with file_name.open('w') as f:
manifest_download_list = []
try:
manifest_download_list.append((repo_data['engines'], 'engine.json'))
except KeyError:
pass
try: try:
manifest_download_list.append((repo_data['projects'], 'project.json')) time_now = datetime.now()
except KeyError: # Convert to lower case because AM/PM is capitalized
pass time_str = time_now.strftime('%d/%m/%Y %I:%M%p').lower()
try: repo_data.update({'last_updated': time_str})
manifest_download_list.append((repo_data['gems'], 'gem.json')) f.write(json.dumps(repo_data, indent=4) + '\n')
except KeyError: except Exception as e:
pass logger.error(f'{file_name} failed to save: {str(e)}')
try: return 1
manifest_download_list.append((repo_data['templates'], 'template.json'))
except KeyError: # A repo may not contain all types of object.
pass manifest_download_list = []
try: try:
manifest_download_list.append((repo_data['restricted'], 'restricted.json')) manifest_download_list.append((repo_data['engines'], 'engine.json'))
except KeyError: except KeyError:
pass pass
try:
manifest_download_list.append((repo_data['projects'], 'project.json'))
except KeyError:
pass
try:
manifest_download_list.append((repo_data['gems'], 'gem.json'))
except KeyError:
pass
try:
manifest_download_list.append((repo_data['templates'], 'template.json'))
except KeyError:
pass
try:
manifest_download_list.append((repo_data['restricted'], 'restricted.json'))
except KeyError:
pass
for o3de_object_uris, manifest_json in manifest_download_list:
for o3de_object_uri in o3de_object_uris:
manifest_json_uri = f'{o3de_object_uri}/{manifest_json}'
manifest_json_sha256 = hashlib.sha256(manifest_json_uri.encode())
cache_file = cache_folder / str(manifest_json_sha256.hexdigest() + '.json')
if not cache_file.is_file():
parsed_uri = urllib.parse.urlparse(manifest_json_uri)
download_file_result = utils.download_file(parsed_uri, cache_file)
if download_file_result != 0:
return download_file_result
for o3de_object_uris, manifest_json in manifest_download_list: # Having a repo is also optional
repo_list = []
try:
repo_list.append(repo_data['repos'])
except KeyError:
pass
for repo in repo_list:
if repo not in repo_set:
repo_set.add(repo)
for o3de_object_uri in o3de_object_uris: for o3de_object_uri in o3de_object_uris:
manifest_json_uri = f'{o3de_object_uri}/{manifest_json}' parsed_uri = urllib.parse.urlparse(f'{repo}/repo.json')
manifest_json_sha256 = hashlib.sha256(manifest_json_uri.encode()) manifest_json_sha256 = hashlib.sha256(parsed_uri.geturl().encode())
cache_file = cache_folder / str(manifest_json_sha256.hexdigest() + '.json') cache_file = cache_folder / str(manifest_json_sha256.hexdigest() + '.json')
if not cache_file.is_file(): if cache_file.is_file():
parsed_uri = urllib.parse.urlparse(manifest_json_uri) cache_file.unlink()
download_file_result = utils.download_file(parsed_uri, cache_file) download_file_result = utils.download_file(parsed_uri, cache_file)
if download_file_result != 0: if download_file_result != 0:
return download_file_result return download_file_result
# Having a repo is also optional
repo_list = []
try:
repo_list.append(repo_data['repos'])
except KeyError:
pass
for repo in repo_list: return process_add_o3de_repo(parsed_uri.geturl(), repo_set)
if repo not in repo_set:
repo_set.add(repo)
for o3de_object_uri in o3de_object_uris:
parsed_uri = urllib.parse.urlparse(f'{repo}/repo.json')
manifest_json_sha256 = hashlib.sha256(parsed_uri.geturl().encode())
cache_file = cache_folder / str(manifest_json_sha256.hexdigest() + '.json')
if cache_file.is_file():
cache_file.unlink()
download_file_result = utils.download_file(parsed_uri, cache_file)
if download_file_result != 0:
return download_file_result
return process_add_o3de_repo(parsed_uri.geturl(), repo_set)
return 0 return 0
@ -141,6 +153,29 @@ def get_gem_json_paths_from_all_cached_repos() -> set:
return gem_set return gem_set
def refresh_repo(repo_uri: str,
cache_folder: str = None,
repo_set: set = None) -> int:
if not cache_folder:
cache_folder = manifest.get_o3de_cache_folder()
if not repo_set:
repo_set = set()
parsed_uri = urllib.parse.urlparse(f'{repo_uri}/repo.json')
repo_sha256 = hashlib.sha256(parsed_uri.geturl().encode())
cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json')
download_file_result = utils.download_file(parsed_uri, cache_file)
if download_file_result != 0:
return download_file_result
if not validation.valid_o3de_repo_json(cache_file):
logger.error(f'Repo json {repo_uri} is not valid.')
cache_file.unlink()
return 1
return process_add_o3de_repo(cache_file, repo_set)
def refresh_repos() -> int: def refresh_repos() -> int:
json_data = manifest.load_o3de_manifest() json_data = manifest.load_o3de_manifest()
@ -158,22 +193,9 @@ def refresh_repos() -> int:
if repo_uri not in repo_set: if repo_uri not in repo_set:
repo_set.add(repo_uri) repo_set.add(repo_uri)
parsed_uri = urllib.parse.urlparse(f'{repo_uri}/repo.json') last_failure = refresh_repo(repo_uri, cache_folder, repo_set)
repo_sha256 = hashlib.sha256(parsed_uri.geturl().encode()) if last_failure:
cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json') result = last_failure
if not cache_file.is_file():
download_file_result = utils.download_file(parsed_uri, cache_file)
if download_file_result != 0:
return download_file_result
if not validation.valid_o3de_repo_json(cache_file):
logger.error(f'Repo json {repo_uri} is not valid.')
cache_file.unlink()
return 1
last_failure = process_add_o3de_repo(cache_file, repo_set)
if last_failure:
result = last_failure
return result return result

Loading…
Cancel
Save