Merge pull request #3440 from aws-lumberyard-dev/Prefab/SaveAllPrefabs
Provide options to save prefabs when saving levels
This commit is contained in:
@@ -342,7 +342,7 @@ namespace AzQtComponents
|
||||
config.toolTipPaddingInPixels = 5;
|
||||
config.headerIconSizeInPixels = CardHeader::defaultIconSize();
|
||||
config.rootLayoutSpacing = 0;
|
||||
config.warningIcon = QStringLiteral(":/Cards/img/UI20/Cards/warning.svg");
|
||||
config.warningIcon = QStringLiteral(":/Notifications/warning.svg");
|
||||
config.warningIconSize = {24, 24};
|
||||
config.disabledIconAlpha = 0.25;
|
||||
|
||||
|
||||
@@ -424,7 +424,6 @@
|
||||
<file>img/UI20/Cards/menu_ico.png</file>
|
||||
<file>img/UI20/Cards/error_icon.png</file>
|
||||
<file>img/UI20/Cards/warning.png</file>
|
||||
<file>img/UI20/Cards/warning.svg</file>
|
||||
<file>img/UI20/Cards/search.png</file>
|
||||
<file>img/UI20/Cards/close.png</file>
|
||||
<file>img/UI20/Cards/error-conclict-state.svg</file>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
@@ -30,6 +30,7 @@
|
||||
<file alias="checkmark.svg">Notifications/checkmark.svg</file>
|
||||
<file alias="download.svg">Notifications/download.svg</file>
|
||||
<file alias="link.svg">Notifications/link.svg</file>
|
||||
<file alias="warning.svg">Notifications/warning.svg</file>
|
||||
</qresource>
|
||||
<qresource prefix="/Outliner">
|
||||
<file alias="sort_a_to_z.svg">Outliner/sort_a_to_z.svg</file>
|
||||
|
||||
+2
@@ -43,6 +43,8 @@ namespace AzToolsFramework
|
||||
|
||||
virtual Prefab::InstanceOptionalReference GetRootPrefabInstance() = 0;
|
||||
|
||||
virtual Prefab::TemplateId GetRootPrefabTemplateId() = 0;
|
||||
|
||||
//! Get all Assets generated by Prefab processing when entering Play-In Editor mode (Ctrl+G)
|
||||
//! /return The vector of Assets generated by Prefab processing
|
||||
virtual const AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& GetPlayInEditorAssetData() = 0;
|
||||
|
||||
+6
@@ -359,6 +359,12 @@ namespace AzToolsFramework
|
||||
return AZStd::nullopt;
|
||||
}
|
||||
|
||||
Prefab::TemplateId PrefabEditorEntityOwnershipService::GetRootPrefabTemplateId()
|
||||
{
|
||||
AZ_Assert(m_rootInstance, "A valid root prefab instance couldn't be found in PrefabEditorEntityOwnershipService.");
|
||||
return m_rootInstance ? m_rootInstance->GetTemplateId() : Prefab::InvalidTemplateId;
|
||||
}
|
||||
|
||||
const AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& PrefabEditorEntityOwnershipService::GetPlayInEditorAssetData()
|
||||
{
|
||||
return m_playInEditorData.m_assets;
|
||||
|
||||
+1
@@ -193,6 +193,7 @@ namespace AzToolsFramework
|
||||
AZ::IO::PathView filePath, Prefab::InstanceOptionalReference instanceToParentUnder) override;
|
||||
|
||||
Prefab::InstanceOptionalReference GetRootPrefabInstance() override;
|
||||
Prefab::TemplateId GetRootPrefabTemplateId() override;
|
||||
|
||||
const AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& GetPlayInEditorAssetData() override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -26,6 +26,19 @@ namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
{
|
||||
static constexpr const char s_saveAllPrefabsKey[] = "/O3DE/Preferences/Prefabs/SaveAllPrefabs";
|
||||
|
||||
void PrefabLoader::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Enum<SaveAllPrefabsPreference>()
|
||||
->Value("Ask every time", SaveAllPrefabsPreference::AskEveryTime)
|
||||
->Value("Save all", SaveAllPrefabsPreference::SaveAll)
|
||||
->Value("Save none", SaveAllPrefabsPreference::SaveNone);
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabLoader::RegisterPrefabLoaderInterface()
|
||||
{
|
||||
m_prefabSystemComponentInterface = AZ::Interface<PrefabSystemComponentInterface>::Get();
|
||||
@@ -657,6 +670,24 @@ namespace AzToolsFramework
|
||||
return finalPath;
|
||||
}
|
||||
|
||||
SaveAllPrefabsPreference PrefabLoader::GetSaveAllPrefabsPreference() const
|
||||
{
|
||||
SaveAllPrefabsPreference saveAllPrefabsPreference = SaveAllPrefabsPreference::AskEveryTime;
|
||||
if (auto* registry = AZ::SettingsRegistry::Get())
|
||||
{
|
||||
registry->GetObject(saveAllPrefabsPreference, s_saveAllPrefabsKey);
|
||||
}
|
||||
return saveAllPrefabsPreference;
|
||||
}
|
||||
|
||||
void PrefabLoader::SetSaveAllPrefabsPreference(SaveAllPrefabsPreference saveAllPrefabsPreference)
|
||||
{
|
||||
if (auto* registry = AZ::SettingsRegistry::Get())
|
||||
{
|
||||
registry->SetObject(s_saveAllPrefabsKey, saveAllPrefabsPreference);
|
||||
}
|
||||
}
|
||||
|
||||
AZ::IO::Path PrefabLoaderInterface::GeneratePath()
|
||||
{
|
||||
return AZStd::string::format("Prefab_%s", AZ::Entity::MakeId().ToString().c_str());
|
||||
|
||||
@@ -39,6 +39,8 @@ namespace AzToolsFramework
|
||||
AZ_CLASS_ALLOCATOR(PrefabLoader, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(PrefabLoader, "{A302B072-4DC4-4B7E-9188-226F56A3429C8}", PrefabLoaderInterface);
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// PrefabLoaderInterface interface implementation
|
||||
|
||||
@@ -108,6 +110,9 @@ namespace AzToolsFramework
|
||||
//! Returns if the path is a valid path for a prefab
|
||||
static bool IsValidPrefabPath(AZ::IO::PathView path);
|
||||
|
||||
SaveAllPrefabsPreference GetSaveAllPrefabsPreference() const override;
|
||||
void SetSaveAllPrefabsPreference(SaveAllPrefabsPreference saveAllPrefabsPreference) override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Copies the template dom provided and manipulates it into the proper format to be saved to disk.
|
||||
|
||||
@@ -17,6 +17,13 @@ namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
{
|
||||
enum class SaveAllPrefabsPreference
|
||||
{
|
||||
AskEveryTime,
|
||||
SaveAll,
|
||||
SaveNone
|
||||
};
|
||||
|
||||
/*!
|
||||
* PrefabLoaderInterface
|
||||
* Interface for saving/loading Prefab files.
|
||||
@@ -84,6 +91,9 @@ namespace AzToolsFramework
|
||||
//! The path will always use the '/' separator.
|
||||
virtual AZ::IO::Path GenerateRelativePath(AZ::IO::PathView path) = 0;
|
||||
|
||||
virtual SaveAllPrefabsPreference GetSaveAllPrefabsPreference() const = 0;
|
||||
virtual void SetSaveAllPrefabsPreference(SaveAllPrefabsPreference saveAllPrefabsPreference) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
// Generates a new path
|
||||
@@ -93,3 +103,8 @@ namespace AzToolsFramework
|
||||
} // namespace Prefab
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
AZ_TYPE_INFO_SPECIALIZE(AzToolsFramework::Prefab::SaveAllPrefabsPreference, "{7E61EA82-4DE4-4A3F-945F-C8FEDC1114B5}");
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ namespace AzToolsFramework
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabCatchmentProcessor::Reflect(context);
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::EditorInfoRemover::Reflect(context);
|
||||
PrefabPublicRequestHandler::Reflect(context);
|
||||
PrefabLoader::Reflect(context);
|
||||
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
@@ -369,9 +370,11 @@ namespace AzToolsFramework
|
||||
PrefabDom& PrefabSystemComponent::FindTemplateDom(TemplateId templateId)
|
||||
{
|
||||
AZStd::optional<AZStd::reference_wrapper<Template>> findTemplateResult = FindTemplate(templateId);
|
||||
AZ_Assert(findTemplateResult.has_value(),
|
||||
AZ_Assert(
|
||||
findTemplateResult.has_value(),
|
||||
"PrefabSystemComponent::FindTemplateDom - Unable to retrieve Prefab template with id: '%llu'. "
|
||||
"Template could not be found", templateId);
|
||||
"Template could not be found",
|
||||
templateId);
|
||||
|
||||
AZ_Assert(findTemplateResult->get().IsValid(),
|
||||
"PrefabSystemComponent::FindTemplateDom - Unable to retrieve Prefab template with id: '%llu'. "
|
||||
@@ -751,6 +754,89 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
bool PrefabSystemComponent::AreDirtyTemplatesPresent(TemplateId rootTemplateId)
|
||||
{
|
||||
TemplateReference prefabTemplate = FindTemplate(rootTemplateId);
|
||||
|
||||
if (!prefabTemplate.has_value())
|
||||
{
|
||||
AZ_Assert(false, "Template with id %llu is not found", rootTemplateId);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsTemplateDirty(rootTemplateId))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const Template::Links& linkIds = prefabTemplate->get().GetLinks();
|
||||
|
||||
for (LinkId linkId : linkIds)
|
||||
{
|
||||
auto linkIterator = m_linkIdMap.find(linkId);
|
||||
if (linkIterator != m_linkIdMap.end())
|
||||
{
|
||||
return AreDirtyTemplatesPresent(linkIterator->second.GetSourceTemplateId());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PrefabSystemComponent::SaveAllDirtyTemplates(TemplateId rootTemplateId)
|
||||
{
|
||||
AZStd::set<AZ::IO::PathView> dirtyTemplatePaths = GetDirtyTemplatePaths(rootTemplateId);
|
||||
|
||||
for (AZ::IO::PathView dirtyTemplatePath : dirtyTemplatePaths)
|
||||
{
|
||||
auto dirtyTemplateIterator = m_templateFilePathToIdMap.find(dirtyTemplatePath);
|
||||
if (dirtyTemplateIterator == m_templateFilePathToIdMap.end())
|
||||
{
|
||||
AZ_Assert(false, "Template id for template with path '%s' is not found.", dirtyTemplatePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_prefabLoader.SaveTemplate(dirtyTemplateIterator->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::set<AZ::IO::PathView> PrefabSystemComponent::GetDirtyTemplatePaths(TemplateId rootTemplateId)
|
||||
{
|
||||
AZStd::vector<AZ::IO::PathView> dirtyTemplatePathVector;
|
||||
GetDirtyTemplatePathsHelper(rootTemplateId, dirtyTemplatePathVector);
|
||||
AZStd::set<AZ::IO::PathView> dirtyTemplatePaths;
|
||||
dirtyTemplatePaths.insert(dirtyTemplatePathVector.begin(), dirtyTemplatePathVector.end());
|
||||
return AZStd::move(dirtyTemplatePaths);
|
||||
}
|
||||
|
||||
void PrefabSystemComponent::GetDirtyTemplatePathsHelper(
|
||||
TemplateId rootTemplateId, AZStd::vector<AZ::IO::PathView>& dirtyTemplatePaths)
|
||||
{
|
||||
TemplateReference prefabTemplate = FindTemplate(rootTemplateId);
|
||||
|
||||
if (!prefabTemplate.has_value())
|
||||
{
|
||||
AZ_Assert(false, "Template with id %llu is not found", rootTemplateId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsTemplateDirty(rootTemplateId))
|
||||
{
|
||||
dirtyTemplatePaths.emplace_back(prefabTemplate->get().GetFilePath());
|
||||
}
|
||||
|
||||
const Template::Links& linkIds = prefabTemplate->get().GetLinks();
|
||||
|
||||
for (LinkId linkId : linkIds)
|
||||
{
|
||||
auto linkIterator = m_linkIdMap.find(linkId);
|
||||
if (linkIterator != m_linkIdMap.end())
|
||||
{
|
||||
GetDirtyTemplatePathsHelper(linkIterator->second.GetSourceTemplateId(), dirtyTemplatePaths);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PrefabSystemComponent::ConnectTemplates(
|
||||
Link& link,
|
||||
TemplateId sourceTemplateId,
|
||||
|
||||
@@ -183,6 +183,12 @@ namespace AzToolsFramework
|
||||
*/
|
||||
void SetTemplateDirtyFlag(const TemplateId& templateId, bool dirty) override;
|
||||
|
||||
bool AreDirtyTemplatesPresent(TemplateId rootTemplateId) override;
|
||||
|
||||
void SaveAllDirtyTemplates(TemplateId rootTemplateId) override;
|
||||
|
||||
AZStd::set<AZ::IO::PathView> GetDirtyTemplatePaths(TemplateId rootTemplateId) override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
@@ -335,6 +341,9 @@ namespace AzToolsFramework
|
||||
*/
|
||||
bool RemoveLinkFromTargetTemplate(const LinkId& linkId, const Link& link);
|
||||
|
||||
// Helper function for GetDirtyTemplatePaths(). It uses vector to speed up iteration times.
|
||||
void GetDirtyTemplatePathsHelper(TemplateId rootTemplateId, AZStd::vector<AZ::IO::PathView>& dirtyTemplatePaths);
|
||||
|
||||
// A container for mapping Templates to the Links they may propagate changes to.
|
||||
AZStd::unordered_map<TemplateId, AZStd::unordered_set<LinkId>> m_templateToLinkIdsMap;
|
||||
|
||||
|
||||
+15
-1
@@ -9,11 +9,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/std/containers/set.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||
#include <AzToolsFramework/Prefab/Link/Link.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabIdTypes.h>
|
||||
#include <AzToolsFramework/Prefab/Template/Template.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
@@ -50,6 +51,19 @@ namespace AzToolsFramework
|
||||
virtual bool IsTemplateDirty(const TemplateId& templateId) = 0;
|
||||
virtual void SetTemplateDirtyFlag(const TemplateId& templateId, bool dirty) = 0;
|
||||
|
||||
//! Recursive function to check if the template is dirty or if any dirty templates are presents in the links of the template.
|
||||
//! @param rootTemplateId The id of the template provided as the beginning template to check the outgoing links.
|
||||
virtual bool AreDirtyTemplatesPresent(TemplateId rootTemplateId) = 0;
|
||||
|
||||
//! Recursive function to save if the template is dirty and save all the dirty templates in the links of the template.
|
||||
//! @param rootTemplateId The id of the template provided as the beginning template to check the outgoing links.
|
||||
virtual void SaveAllDirtyTemplates(TemplateId rootTemplateId) = 0;
|
||||
|
||||
//! Recursive function that fetches the set of dirty templates given a starting template to check for outgoing links.
|
||||
//! @param rootTemplateId The id of the template provided as the beginning template to check the outgoing links.
|
||||
//! @return The set of dirty template paths populated.
|
||||
virtual AZStd::set<AZ::IO::PathView> GetDirtyTemplatePaths(TemplateId rootTemplateId) = 0;
|
||||
|
||||
virtual PrefabDom& FindTemplateDom(TemplateId templateId) = 0;
|
||||
virtual void UpdatePrefabTemplate(TemplateId templateId, const PrefabDom& updatedDom) = 0;
|
||||
virtual void PropagateTemplateChanges(TemplateId templateId, InstanceOptionalReference instanceToExclude = AZStd::nullopt) = 0;
|
||||
|
||||
+10
@@ -11,6 +11,7 @@
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabIdTypes.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
@@ -28,6 +29,15 @@ namespace AzToolsFramework
|
||||
* @return The id of the newly created entity.
|
||||
*/
|
||||
virtual AZ::EntityId CreateNewEntityAtPosition(const AZ::Vector3& position, AZ::EntityId parentId) = 0;
|
||||
|
||||
//! Constructs and executes the close dialog on a prefab template corresponding to templateId.
|
||||
//! @param templateId The id of the template the user chose to close.
|
||||
virtual int ExecuteClosePrefabDialog(TemplateId templateId) = 0;
|
||||
|
||||
//! Constructs and executes the save dialog on a prefab template corresponding to templateId.
|
||||
//! @param templateId The id of the template the user chose to save.
|
||||
//! @param useSaveAllPrefabsPreference A flag indicating whether SaveAllPrefabsPreference should be used for saving templates.
|
||||
virtual void ExecuteSavePrefabDialog(TemplateId templateId, bool useSaveAllPrefabsPreference = false) = 0;
|
||||
};
|
||||
|
||||
} // namespace Prefab
|
||||
|
||||
+269
@@ -12,6 +12,7 @@
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
#include <AzFramework/Asset/AssetSystemBus.h>
|
||||
@@ -27,12 +28,28 @@
|
||||
#include <AzToolsFramework/UI/Prefab/PrefabIntegrationInterface.h>
|
||||
#include <AzToolsFramework/UI/UICore/WidgetHelpers.h>
|
||||
|
||||
#include <AzQtComponents/Components/Widgets/CheckBox.h>
|
||||
#include <AzQtComponents/Components/FlowLayout.h>
|
||||
#include <AzQtComponents/Components/StyleManager.h>
|
||||
#include <AzQtComponents/Components/Widgets/CardHeader.h>
|
||||
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCheckBox>
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QFrame>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QMainWindow>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <QScrollArea>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
@@ -43,8 +60,19 @@ namespace AzToolsFramework
|
||||
PrefabPublicInterface* PrefabIntegrationManager::s_prefabPublicInterface = nullptr;
|
||||
PrefabEditInterface* PrefabIntegrationManager::s_prefabEditInterface = nullptr;
|
||||
PrefabLoaderInterface* PrefabIntegrationManager::s_prefabLoaderInterface = nullptr;
|
||||
PrefabSystemComponentInterface* PrefabIntegrationManager::s_prefabSystemComponentInterface = nullptr;
|
||||
|
||||
const AZStd::string PrefabIntegrationManager::s_prefabFileExtension = ".prefab";
|
||||
|
||||
static const char* const ClosePrefabDialog = "ClosePrefabDialog";
|
||||
static const char* const FooterSeparatorLine = "FooterSeparatorLine";
|
||||
static const char* const PrefabSavedMessageFrame = "PrefabSavedMessageFrame";
|
||||
static const char* const PrefabSavePreferenceHint = "PrefabSavePreferenceHint";
|
||||
static const char* const PrefabSaveWarningFrame = "PrefabSaveWarningFrame";
|
||||
static const char* const SaveDependentPrefabsCard = "SaveDependentPrefabsCard";
|
||||
static const char* const SavePrefabDialog = "SavePrefabDialog";
|
||||
static const char* const UnsavedPrefabFileName = "UnsavedPrefabFileName";
|
||||
|
||||
|
||||
void PrefabUserSettings::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
@@ -88,6 +116,13 @@ namespace AzToolsFramework
|
||||
return;
|
||||
}
|
||||
|
||||
s_prefabSystemComponentInterface = AZ::Interface<PrefabSystemComponentInterface>::Get();
|
||||
if (s_prefabSystemComponentInterface == nullptr)
|
||||
{
|
||||
AZ_Assert(false, "Prefab - could not get PrefabSystemComponentInterface on PrefabIntegrationManager construction.");
|
||||
return;
|
||||
}
|
||||
|
||||
EditorContextMenuBus::Handler::BusConnect();
|
||||
PrefabInstanceContainerNotificationBus::Handler::BusConnect();
|
||||
AZ::Interface<PrefabIntegrationInterface>::Register(this);
|
||||
@@ -1050,5 +1085,239 @@ namespace AzToolsFramework
|
||||
return AZ::EntityId();
|
||||
}
|
||||
}
|
||||
|
||||
int PrefabIntegrationManager::ExecuteClosePrefabDialog(TemplateId templateId)
|
||||
{
|
||||
if (s_prefabSystemComponentInterface->AreDirtyTemplatesPresent(templateId))
|
||||
{
|
||||
auto prefabSaveSelectionDialog = ConstructClosePrefabDialog(templateId);
|
||||
|
||||
int prefabSaveSelection = prefabSaveSelectionDialog->exec();
|
||||
|
||||
if (prefabSaveSelection == QDialog::Accepted)
|
||||
{
|
||||
SavePrefabsInDialog(prefabSaveSelectionDialog.get());
|
||||
}
|
||||
|
||||
return prefabSaveSelection;
|
||||
}
|
||||
|
||||
return QDialogButtonBox::DestructiveRole;
|
||||
}
|
||||
|
||||
void PrefabIntegrationManager::ExecuteSavePrefabDialog(TemplateId templateId, bool useSaveAllPrefabsPreference)
|
||||
{
|
||||
auto prefabTemplate = s_prefabSystemComponentInterface->FindTemplate(templateId);
|
||||
AZ::IO::Path prefabTemplatePath = prefabTemplate->get().GetFilePath();
|
||||
|
||||
if (s_prefabSystemComponentInterface->IsTemplateDirty(templateId))
|
||||
{
|
||||
if (s_prefabLoaderInterface->SaveTemplate(templateId) == false)
|
||||
{
|
||||
AZ_Error("Prefab", false, "Template '%s' could not be saved successfully.", prefabTemplatePath.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (s_prefabSystemComponentInterface->AreDirtyTemplatesPresent(templateId))
|
||||
{
|
||||
if (useSaveAllPrefabsPreference)
|
||||
{
|
||||
SaveAllPrefabsPreference saveAllPrefabsPreference = s_prefabLoaderInterface->GetSaveAllPrefabsPreference();
|
||||
|
||||
if (saveAllPrefabsPreference == SaveAllPrefabsPreference::SaveAll)
|
||||
{
|
||||
s_prefabSystemComponentInterface->SaveAllDirtyTemplates(templateId);
|
||||
return;
|
||||
}
|
||||
else if (saveAllPrefabsPreference == SaveAllPrefabsPreference::SaveNone)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<QDialog> savePrefabDialog = ConstructSavePrefabDialog(templateId, useSaveAllPrefabsPreference);
|
||||
if (savePrefabDialog)
|
||||
{
|
||||
int prefabSaveSelection = savePrefabDialog->exec();
|
||||
|
||||
if (prefabSaveSelection == QDialog::Accepted)
|
||||
{
|
||||
SavePrefabsInDialog(savePrefabDialog.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabIntegrationManager::SavePrefabsInDialog(QDialog* unsavedPrefabsDialog)
|
||||
{
|
||||
QList<QLabel*> unsavedPrefabFileLabels = unsavedPrefabsDialog->findChildren<QLabel*>(UnsavedPrefabFileName);
|
||||
if (unsavedPrefabFileLabels.size() > 0)
|
||||
{
|
||||
for (const QLabel* unsavedPrefabFileLabel : unsavedPrefabFileLabels)
|
||||
{
|
||||
AZStd::string unsavedPrefabFileName = unsavedPrefabFileLabel->property("FilePath").toString().toUtf8().data();
|
||||
AzToolsFramework::Prefab::TemplateId unsavedPrefabTemplateId =
|
||||
s_prefabSystemComponentInterface->GetTemplateIdFromFilePath(unsavedPrefabFileName.data());
|
||||
bool isTemplateSavedSuccessfully = s_prefabLoaderInterface->SaveTemplate(unsavedPrefabTemplateId);
|
||||
AZ_Error("Prefab", isTemplateSavedSuccessfully, "Prefab '%s' could not be saved successfully.", unsavedPrefabFileName.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<QDialog> PrefabIntegrationManager::ConstructSavePrefabDialog(TemplateId templateId, bool useSaveAllPrefabsPreference)
|
||||
{
|
||||
AZStd::unique_ptr<QDialog> savePrefabDialog = AZStd::make_unique<QDialog>(AzToolsFramework::GetActiveWindow());
|
||||
|
||||
savePrefabDialog->setWindowTitle("Unsaved files detected");
|
||||
|
||||
// Main Content section begins.
|
||||
savePrefabDialog->setObjectName(SavePrefabDialog);
|
||||
QBoxLayout* contentLayout = new QVBoxLayout(savePrefabDialog.get());
|
||||
|
||||
QFrame* prefabSavedMessageFrame = new QFrame(savePrefabDialog.get());
|
||||
QHBoxLayout* prefabSavedMessageLayout = new QHBoxLayout(savePrefabDialog.get());
|
||||
prefabSavedMessageFrame->setObjectName(PrefabSavedMessageFrame);
|
||||
prefabSavedMessageFrame->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
|
||||
|
||||
// Add a checkMark icon next to the level entities saved message.
|
||||
QPixmap checkMarkIcon(QString(":/Notifications/checkmark.svg"));
|
||||
QLabel* prefabSavedSuccessfullyIconContainer = new QLabel(savePrefabDialog.get());
|
||||
prefabSavedSuccessfullyIconContainer->setPixmap(checkMarkIcon);
|
||||
prefabSavedSuccessfullyIconContainer->setFixedWidth(checkMarkIcon.width());
|
||||
|
||||
// Add a message that level entities are saved successfully.
|
||||
|
||||
auto prefabTemplate = s_prefabSystemComponentInterface->FindTemplate(templateId);
|
||||
AZ::IO::Path prefabTemplatePath = prefabTemplate->get().GetFilePath();
|
||||
QLabel* prefabSavedSuccessfullyLabel = new QLabel(
|
||||
QString("Prefab '<b>%1</b>' has been saved. Do you want to save the below dependent prefabs too?").arg(prefabTemplatePath.c_str()),
|
||||
savePrefabDialog.get());
|
||||
prefabSavedMessageLayout->addWidget(prefabSavedSuccessfullyIconContainer);
|
||||
prefabSavedMessageLayout->addWidget(prefabSavedSuccessfullyLabel);
|
||||
prefabSavedMessageFrame->setLayout(prefabSavedMessageLayout);
|
||||
contentLayout->addWidget(prefabSavedMessageFrame);
|
||||
|
||||
AZStd::unique_ptr<AzQtComponents::Card> unsavedPrefabsContainer = ConstructUnsavedPrefabsCard(templateId);
|
||||
contentLayout->addWidget(unsavedPrefabsContainer.release());
|
||||
|
||||
contentLayout->addStretch();
|
||||
|
||||
// Footer section begins.
|
||||
QHBoxLayout* footerLayout = new QHBoxLayout(savePrefabDialog.get());
|
||||
|
||||
if (useSaveAllPrefabsPreference)
|
||||
{
|
||||
QFrame* footerSeparatorLine = new QFrame(savePrefabDialog.get());
|
||||
footerSeparatorLine->setObjectName(FooterSeparatorLine);
|
||||
footerSeparatorLine->setFrameShape(QFrame::HLine);
|
||||
contentLayout->addWidget(footerSeparatorLine);
|
||||
|
||||
QLabel* prefabSavePreferenceHint = new QLabel(
|
||||
"<u>You can prevent this window from showing in the future by updating your global save preferences.</u>",
|
||||
savePrefabDialog.get());
|
||||
prefabSavePreferenceHint->setToolTip(
|
||||
"Go to 'Edit > Editor Settings > Global Preferences... > Global save preferences' to update your preference");
|
||||
prefabSavePreferenceHint->setObjectName(PrefabSavePreferenceHint);
|
||||
footerLayout->addWidget(prefabSavePreferenceHint);
|
||||
}
|
||||
|
||||
QDialogButtonBox* prefabSaveConfirmationButtons =
|
||||
new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::No, savePrefabDialog.get());
|
||||
footerLayout->addWidget(prefabSaveConfirmationButtons);
|
||||
contentLayout->addLayout(footerLayout);
|
||||
connect(prefabSaveConfirmationButtons, &QDialogButtonBox::accepted, savePrefabDialog.get(), &QDialog::accept);
|
||||
connect(prefabSaveConfirmationButtons, &QDialogButtonBox::rejected, savePrefabDialog.get(), &QDialog::reject);
|
||||
AzQtComponents::StyleManager::setStyleSheet(savePrefabDialog->parentWidget(), QStringLiteral("style:Editor.qss"));
|
||||
|
||||
savePrefabDialog->setLayout(contentLayout);
|
||||
return AZStd::move(savePrefabDialog);
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<QDialog> PrefabIntegrationManager::ConstructClosePrefabDialog(TemplateId templateId)
|
||||
{
|
||||
AZStd::shared_ptr<QDialog> closePrefabDialog = AZStd::make_shared<QDialog>(AzToolsFramework::GetActiveWindow());
|
||||
closePrefabDialog->setWindowTitle("Unsaved files detected");
|
||||
AZStd::weak_ptr<QDialog> closePrefabDialogWeakPtr(closePrefabDialog);
|
||||
closePrefabDialog->setObjectName(ClosePrefabDialog);
|
||||
|
||||
// Main Content section begins.
|
||||
QVBoxLayout* contentLayout = new QVBoxLayout(closePrefabDialog.get());
|
||||
QFrame* prefabSaveWarningFrame = new QFrame(closePrefabDialog.get());
|
||||
QHBoxLayout* levelEntitiesSaveQuestionLayout = new QHBoxLayout(closePrefabDialog.get());
|
||||
prefabSaveWarningFrame->setObjectName(PrefabSaveWarningFrame);
|
||||
|
||||
// Add a warning icon next to save prefab warning.
|
||||
prefabSaveWarningFrame->setLayout(levelEntitiesSaveQuestionLayout);
|
||||
QPixmap warningIcon(QString(":/Notifications/warning.svg"));
|
||||
QLabel* warningIconContainer = new QLabel(closePrefabDialog.get());
|
||||
warningIconContainer->setPixmap(warningIcon);
|
||||
warningIconContainer->setFixedWidth(warningIcon.width());
|
||||
levelEntitiesSaveQuestionLayout->addWidget(warningIconContainer);
|
||||
|
||||
// Ask user if they want to save entities in level.
|
||||
QLabel* prefabSaveQuestionLabel = new QLabel("Do you want to save the below unsaved prefabs?", closePrefabDialog.get());
|
||||
levelEntitiesSaveQuestionLayout->addWidget(prefabSaveQuestionLabel);
|
||||
contentLayout->addWidget(prefabSaveWarningFrame);
|
||||
|
||||
auto templateToSave = s_prefabSystemComponentInterface->FindTemplate(templateId);
|
||||
AZ::IO::Path templateToSaveFilePath = templateToSave->get().GetFilePath();
|
||||
AZStd::unique_ptr<AzQtComponents::Card> unsavedPrefabsCard = ConstructUnsavedPrefabsCard(templateId);
|
||||
contentLayout->addWidget(unsavedPrefabsCard.release());
|
||||
|
||||
contentLayout->addStretch();
|
||||
|
||||
QHBoxLayout* footerLayout = new QHBoxLayout(closePrefabDialog.get());
|
||||
|
||||
QDialogButtonBox* prefabSaveConfirmationButtons = new QDialogButtonBox(
|
||||
QDialogButtonBox::Save | QDialogButtonBox::Discard | QDialogButtonBox::Cancel, closePrefabDialog.get());
|
||||
footerLayout->addWidget(prefabSaveConfirmationButtons);
|
||||
contentLayout->addLayout(footerLayout);
|
||||
QObject::connect(prefabSaveConfirmationButtons, &QDialogButtonBox::accepted, closePrefabDialog.get(), &QDialog::accept);
|
||||
QObject::connect(prefabSaveConfirmationButtons, &QDialogButtonBox::rejected, closePrefabDialog.get(), &QDialog::reject);
|
||||
QObject::connect(
|
||||
prefabSaveConfirmationButtons, &QDialogButtonBox::clicked, closePrefabDialog.get(),
|
||||
[closePrefabDialogWeakPtr, prefabSaveConfirmationButtons](QAbstractButton* button)
|
||||
{
|
||||
int prefabSaveSelection = prefabSaveConfirmationButtons->buttonRole(button);
|
||||
closePrefabDialogWeakPtr.lock()->done(prefabSaveSelection);
|
||||
});
|
||||
AzQtComponents::StyleManager::setStyleSheet(closePrefabDialog.get(), QStringLiteral("style:Editor.qss"));
|
||||
closePrefabDialog->setLayout(contentLayout);
|
||||
return closePrefabDialog;
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<AzQtComponents::Card> PrefabIntegrationManager::ConstructUnsavedPrefabsCard(TemplateId templateId)
|
||||
{
|
||||
FlowLayout* unsavedPrefabsLayout = new FlowLayout(AzToolsFramework::GetActiveWindow());
|
||||
|
||||
AZStd::set<AZ::IO::PathView> dirtyTemplatePaths = s_prefabSystemComponentInterface->GetDirtyTemplatePaths(templateId);
|
||||
|
||||
for (AZ::IO::PathView dirtyTemplatePath : dirtyTemplatePaths)
|
||||
{
|
||||
QLabel* prefabNameLabel =
|
||||
new QLabel(QString("<u>%1</u>").arg(dirtyTemplatePath.Filename().Native().data()), AzToolsFramework::GetActiveWindow());
|
||||
prefabNameLabel->setObjectName(UnsavedPrefabFileName);
|
||||
prefabNameLabel->setWordWrap(true);
|
||||
prefabNameLabel->setToolTip(dirtyTemplatePath.Native().data());
|
||||
prefabNameLabel->setProperty("FilePath", dirtyTemplatePath.Native().data());
|
||||
unsavedPrefabsLayout->addWidget(prefabNameLabel);
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<AzQtComponents::Card> unsavedPrefabsContainer = AZStd::make_unique<AzQtComponents::Card>(AzToolsFramework::GetActiveWindow());
|
||||
unsavedPrefabsContainer->setObjectName(SaveDependentPrefabsCard);
|
||||
unsavedPrefabsContainer->setTitle("Unsaved Prefabs");
|
||||
unsavedPrefabsContainer->header()->setHasContextMenu(false);
|
||||
unsavedPrefabsContainer->header()->setIcon(QIcon(QStringLiteral(":/Entity/prefab_edit.svg")));
|
||||
|
||||
QFrame* unsavedPrefabsFrame = new QFrame(unsavedPrefabsContainer.get());
|
||||
unsavedPrefabsFrame->setLayout(unsavedPrefabsLayout);
|
||||
QScrollArea* unsavedPrefabsScrollArea = new QScrollArea(unsavedPrefabsContainer.get());
|
||||
unsavedPrefabsScrollArea->setWidget(unsavedPrefabsFrame);
|
||||
unsavedPrefabsScrollArea->setWidgetResizable(true);
|
||||
unsavedPrefabsContainer->setContentWidget(unsavedPrefabsScrollArea);
|
||||
|
||||
return AZStd::move(unsavedPrefabsContainer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,12 +15,15 @@
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserSourceDropBus.h>
|
||||
#include <AzToolsFramework/Editor/EditorContextMenuBus.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h>
|
||||
#include <AzToolsFramework/UI/Prefab/LevelRootUiHandler.h>
|
||||
#include <AzToolsFramework/UI/Prefab/PrefabEditManager.h>
|
||||
#include <AzToolsFramework/UI/Prefab/PrefabIntegrationBus.h>
|
||||
#include <AzToolsFramework/UI/Prefab/PrefabIntegrationInterface.h>
|
||||
#include <AzToolsFramework/UI/Prefab/PrefabUiHandler.h>
|
||||
|
||||
#include <AzQtComponents/Components/Widgets/Card.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
@@ -49,6 +52,7 @@ namespace AzToolsFramework
|
||||
, public AssetBrowser::AssetBrowserSourceDropBus::Handler
|
||||
, public PrefabInstanceContainerNotificationBus::Handler
|
||||
, public PrefabIntegrationInterface
|
||||
, public QObject
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(PrefabIntegrationManager, AZ::SystemAllocator, 0);
|
||||
@@ -72,6 +76,8 @@ namespace AzToolsFramework
|
||||
|
||||
// PrefabIntegrationInterface...
|
||||
AZ::EntityId CreateNewEntityAtPosition(const AZ::Vector3& position, AZ::EntityId parentId) override;
|
||||
int ExecuteClosePrefabDialog(TemplateId templateId) override;
|
||||
void ExecuteSavePrefabDialog(TemplateId templateId, bool useSaveAllPrefabsPreference) override;
|
||||
|
||||
private:
|
||||
// Manages the Edit Mode UI for prefabs
|
||||
@@ -124,12 +130,19 @@ namespace AzToolsFramework
|
||||
|
||||
static AZ::u32 GetSliceFlags(const AZ::Edit::ElementData* editData, const AZ::Edit::ClassData* classData);
|
||||
|
||||
AZStd::shared_ptr<QDialog> ConstructClosePrefabDialog(TemplateId templateId);
|
||||
AZStd::unique_ptr<AzQtComponents::Card> ConstructUnsavedPrefabsCard(TemplateId templateId);
|
||||
AZStd::unique_ptr<QDialog> ConstructSavePrefabDialog(TemplateId templateId, bool useSaveAllPrefabsPreference);
|
||||
void SavePrefabsInDialog(QDialog* unsavedPrefabsDialog);
|
||||
|
||||
|
||||
static const AZStd::string s_prefabFileExtension;
|
||||
|
||||
static EditorEntityUiInterface* s_editorEntityUiInterface;
|
||||
static PrefabPublicInterface* s_prefabPublicInterface;
|
||||
static PrefabEditInterface* s_prefabEditInterface;
|
||||
static PrefabLoaderInterface* s_prefabLoaderInterface;
|
||||
static PrefabSystemComponentInterface* s_prefabSystemComponentInterface;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user