diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp index 9342c17a37..d5b903585e 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -208,6 +209,9 @@ void SandboxIntegrationManager::Setup() m_editorEntityAPI = AZ::Interface::Get(); AZ_Assert(m_editorEntityAPI, "SandboxIntegrationManager requires an EditorEntityAPI instance to be present on Setup()."); + m_readOnlyEntityPublicInterface = AZ::Interface::Get(); + AZ_Assert(m_readOnlyEntityPublicInterface, "SandboxIntegrationManager requires an ReadOnlyEntityPublicInterface instance to be present on Setup()."); + AzToolsFramework::Layers::EditorLayerComponentNotificationBus::Handler::BusConnect(); } @@ -658,15 +662,17 @@ void SandboxIntegrationManager::PopulateEditorGlobalContextMenu(QMenu* menu, con // when a single entity is selected, entity is created as its child else if (selected.size() == 1) { + AZ::EntityId selectedEntityId = selected.front(); + bool selectedEntityIsReadOnly = m_readOnlyEntityPublicInterface->IsReadOnly(selectedEntityId); auto containerEntityInterface = AZ::Interface::Get(); - if (!prefabSystemEnabled || (containerEntityInterface && containerEntityInterface->IsContainerOpen(selected.front()))) + if (!prefabSystemEnabled || (containerEntityInterface && containerEntityInterface->IsContainerOpen(selectedEntityId) && !selectedEntityIsReadOnly)) { action = menu->addAction(QObject::tr("Create entity")); QObject::connect( action, &QAction::triggered, action, - [selected] + [selectedEntityId] { - AzToolsFramework::EditorRequestBus::Broadcast(&AzToolsFramework::EditorRequestBus::Handler::CreateNewEntityAsChild, selected.front()); + AzToolsFramework::EditorRequestBus::Broadcast(&AzToolsFramework::EditorRequestBus::Handler::CreateNewEntityAsChild, selectedEntityId); } ); } @@ -691,11 +697,27 @@ void SandboxIntegrationManager::PopulateEditorGlobalContextMenu(QMenu* menu, con SetupSliceContextMenu(menu); } - action = menu->addAction(QObject::tr("Duplicate")); - QObject::connect(action, &QAction::triggered, action, [this] { ContextMenu_Duplicate(); }); - if (selected.size() == 0) + if (!selected.empty()) { - action->setDisabled(true); + // Don't allow duplication if any of the selected entities are direct desendants of a read-only entity + bool selectionContainsDescendantOfReadOnlyEntity = false; + for (const auto& entityId : selected) + { + AZ::EntityId parentEntityId; + AZ::TransformBus::EventResult(parentEntityId, entityId, &AZ::TransformBus::Events::GetParentId); + + if (parentEntityId.IsValid() && m_readOnlyEntityPublicInterface->IsReadOnly(parentEntityId)) + { + selectionContainsDescendantOfReadOnlyEntity = true; + break; + } + } + + if (!selectionContainsDescendantOfReadOnlyEntity) + { + action = menu->addAction(QObject::tr("Duplicate")); + QObject::connect(action, &QAction::triggered, action, [this] { ContextMenu_Duplicate(); }); + } } if (!prefabSystemEnabled) diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h index 7fe2881b92..79e7a4334d 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h @@ -76,6 +76,7 @@ namespace AzToolsFramework { class EditorEntityAPI; class EditorEntityUiInterface; + class ReadOnlyEntityPublicInterface; namespace AssetBrowser { @@ -295,6 +296,7 @@ private: AzToolsFramework::EditorEntityUiInterface* m_editorEntityUiInterface = nullptr; AzToolsFramework::Prefab::PrefabIntegrationInterface* m_prefabIntegrationInterface = nullptr; AzToolsFramework::EditorEntityAPI* m_editorEntityAPI = nullptr; + AzToolsFramework::ReadOnlyEntityPublicInterface* m_readOnlyEntityPublicInterface = nullptr; // Overrides UI styling and behavior for Layer Entities AzToolsFramework::LayerUiHandler m_layerUiOverrideHandler; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index dfabd42cd1..aaf6141e12 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -581,7 +582,15 @@ namespace AzToolsFramework "Cannot add entity because the parent entity (id '%llu') is a closed container entity.", static_cast(parentId))); } - + + // If the parent entity is marked as read only, bail. + if (auto readOnlyEntityPublicInterface = AZ::Interface::Get(); readOnlyEntityPublicInterface->IsReadOnly(parentId)) + { + return AZ::Failure(AZStd::string::format( + "Cannot add entity because the parent entity (id '%llu') is marked as read only.", + static_cast(parentId))); + } + EntityAlias entityAlias = Instance::GenerateEntityAlias(); AliasPath absoluteEntityPath = owningInstanceOfParentEntity->get().GetAbsoluteInstanceAliasPath(); @@ -1210,6 +1219,27 @@ namespace AzToolsFramework return AZ::Failure(AZStd::string("Cannot delete entities belonging to an instance that is not being edited.")); } + // None of the specified entities can be marked as read only, otherwise this operation is invalid. + if (auto readOnlyEntityPublicInterface = AZ::Interface::Get()) + { + AZ::EntityId readOnlyEntityId; + for (const auto& entityId : entityIdsNoFocusContainer) + { + if (readOnlyEntityPublicInterface->IsReadOnly(entityId)) + { + readOnlyEntityId = entityId; + break; + } + } + + if (readOnlyEntityId.IsValid()) + { + return AZ::Failure(AZStd::string::format( + "Cannot delete entities because entity (id '%llu') is marked as read only.", + static_cast(readOnlyEntityId))); + } + } + // Retrieve entityList from entityIds EntityList inputEntityList = EntityIdListToEntityList(entityIdsNoFocusContainer); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp index 1c60b78322..d020391665 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -141,6 +142,9 @@ namespace AzToolsFramework return; } + m_readOnlyEntityPublicInterface = AZ::Interface::Get(); + AZ_Assert(m_readOnlyEntityPublicInterface, "Prefab - could not get ReadOnlyEntityPublicInterface on PrefabIntegrationManager construction."); + // Get EditorEntityContextId EditorEntityContextRequestBus::BroadcastResult(s_editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId); @@ -263,6 +267,16 @@ namespace AzToolsFramework AzFramework::ApplicationRequests::Bus::BroadcastResult( prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled); + bool readOnlyEntityInSelection = false; + for (const auto& entityId : selectedEntities) + { + if (m_readOnlyEntityPublicInterface->IsReadOnly(entityId)) + { + readOnlyEntityInSelection = true; + break; + } + } + // Create Prefab { if (!selectedEntities.empty()) @@ -289,7 +303,8 @@ namespace AzToolsFramework } // Layers can't be in prefabs. - if (!layerInSelection) + // Also don't allow to create a prefab if any of the selected entities are read-only + if (!layerInSelection && !readOnlyEntityInSelection) { QAction* createAction = menu->addAction(QObject::tr("Create Prefab...")); createAction->setToolTip(QObject::tr("Creates a prefab out of the currently selected entities.")); @@ -383,14 +398,13 @@ namespace AzToolsFramework menu->addSeparator(); } - QAction* deleteAction = menu->addAction(QObject::tr("Delete")); - QObject::connect(deleteAction, &QAction::triggered, deleteAction, [] { ContextMenu_DeleteSelected(); }); - - if (selectedEntities.empty() || - (selectedEntities.size() == 1 && - selectedEntities[0] == s_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(s_editorEntityContextId))) + if (!selectedEntities.empty() && + (selectedEntities.size() != 1 || + selectedEntities[0] != s_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(s_editorEntityContextId)) && + !readOnlyEntityInSelection) { - deleteAction->setDisabled(true); + QAction* deleteAction = menu->addAction(QObject::tr("Delete")); + QObject::connect(deleteAction, &QAction::triggered, deleteAction, [] { ContextMenu_DeleteSelected(); }); } // Detach Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h index 8589bee942..12aa3f7c72 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h @@ -29,6 +29,7 @@ namespace AzToolsFramework { class ContainerEntityInterface; + class ReadOnlyEntityPublicInterface; namespace Prefab { @@ -169,6 +170,8 @@ namespace AzToolsFramework static PrefabLoaderInterface* s_prefabLoaderInterface; static PrefabPublicInterface* s_prefabPublicInterface; static PrefabSystemComponentInterface* s_prefabSystemComponentInterface; + + ReadOnlyEntityPublicInterface* m_readOnlyEntityPublicInterface = nullptr; }; } }