Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 151 additions & 1 deletion lib/usdUfe/ufe/UsdUndoDeleteCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,90 @@
#include <usdUfe/ufe/UsdAttributes.h>
#endif

#include <ufe/pathString.h>

namespace {

// Validate that a prim can be deleted in a component stage.
// Components only allow deleting prims whose path is contained within
// either the material or geometry scope
void validateComponentDelete(const PXR_NS::UsdPrim& prim)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so i guess youll move this to a shared h/cpp

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, exactly!

{
const PXR_NS::UsdStagePtr stage = prim.GetStage();
if (!stage) {
return;
}

// Get the prim path
const PXR_NS::SdfPath primPath = prim.GetPath();

// Get the default prim to construct full scope paths
auto defaultPrim = stage->GetDefaultPrim();
if (!defaultPrim) {
return;
}
const PXR_NS::SdfPath defaultPrimPath = defaultPrim.GetPath();

// Don't allow deleting the default prim itself
if (primPath == defaultPrimPath) {
const std::string error = PXR_NS::TfStringPrintf(
"Cannot delete prim \"%s\" in a component stage. "
"This is the default prim.",
primPath.GetText());
TF_WARN("%s", error.c_str());
throw std::runtime_error(error);
}

// Get material and mesh scope names from component
std::string materialScopeName = UsdUfe::getComponentMaterialScopeName(stage);
std::string meshScopeName = UsdUfe::getComponentMeshScopeName(stage);

// Build full scope paths
std::vector<PXR_NS::SdfPath> scopePaths;
if (!materialScopeName.empty()) {
scopePaths.push_back(defaultPrimPath.AppendChild(PXR_NS::TfToken(materialScopeName)));
}
if (!meshScopeName.empty()) {
scopePaths.push_back(defaultPrimPath.AppendChild(PXR_NS::TfToken(meshScopeName)));
}

// Don't allow deleting the scope prims themselves
for (const PXR_NS::SdfPath& scopePath : scopePaths) {
if (primPath == scopePath) {
const std::string error = PXR_NS::TfStringPrintf(
"Cannot delete prim \"%s\" in a component stage. "
"This is a protected scope.",
primPath.GetText());
TF_WARN("%s", error.c_str());
throw std::runtime_error(error);
}
}

// Check if the prim path is contained within any of the scope paths
bool isInScope = false;
for (const PXR_NS::SdfPath& scopePath : scopePaths) {
if (primPath.HasPrefix(scopePath)) {
isInScope = true;
break;
}
}

// Allow if prim is within a component scope
if (isInScope) {
return;
}

// Disallow - prim is not in component scopes
const std::string error = PXR_NS::TfStringPrintf(
"Cannot delete prim \"%s\" in a component stage. "
"Only prims within component material or mesh scopes can be deleted. ",
primPath.GetText());
TF_WARN("%s", error.c_str());
throw std::runtime_error(error);
}

} // namespace

namespace USDUFE_NS_DEF {

USDUFE_VERIFY_CLASS_SETUP(Ufe::UndoableCommand, UsdUndoDeleteCommand);
Expand Down Expand Up @@ -75,7 +159,73 @@ void UsdUndoDeleteCommand::execute()
throw std::runtime_error(error);
}

if (!routingEditTarget.IsNull()) {
// Check if this is a component stage
const Ufe::Path proxyPath = UsdUfe::stagePath(stage);
const bool isComponent = UsdUfe::isComponentStage(proxyPath);

if (isComponent) {
// Validate that the prim can be deleted in a component stage
validateComponentDelete(_prim);

// Get all prim specs from all layers (including non-local layers like payloads)
const PXR_NS::SdfPrimSpecHandleVector primStack = _prim.GetPrimStack();

for (const PXR_NS::SdfPrimSpecHandle& primSpec : primStack) {
if (!primSpec)
continue;

const PXR_NS::SdfLayerHandle layer = primSpec->GetLayer();
if (!layer)
continue;

const PXR_NS::SdfPath primPath = primSpec->GetPath();

// DEBUG: Print primspec information
TF_WARN("DEBUG: Component delete - PrimSpec path: %s", primPath.GetText());
TF_WARN("DEBUG: Component delete - Layer: %s", layer->GetDisplayName().c_str());
TF_WARN("DEBUG: Component delete - Layer identifier: %s",
layer->GetIdentifier().c_str());
TF_WARN("DEBUG: Component delete - PrimSpec specifier: %s",
TfEnum::GetName(primSpec->GetSpecifier()).c_str());

UsdUfe::UsdUndoManager::instance().trackLayerStates(layer);

// Get the parent spec
PXR_NS::SdfPrimSpecHandle parent = primSpec->GetRealNameParent();
if (!parent) {
const std::string error = TfStringPrintf(
"Failed to get parent for prim \"%s\" in layer \"%s\".",
primPath.GetText(),
layer->GetDisplayName().c_str());
TF_WARN("%s", error.c_str());
throw std::runtime_error(error);
}

// DEBUG: Print parent information
TF_WARN("DEBUG: Component delete - Parent path: %s", parent->GetPath().GetText());
TF_WARN("DEBUG: Component delete - Parent specifier: %s",
TfEnum::GetName(parent->GetSpecifier()).c_str());
TF_WARN("DEBUG: Component delete - Parent has %zu children",
parent->GetNameChildren().size());

// Remove the prim spec from its parent
if (!parent->RemoveNameChild(primSpec)) {
const std::string error = TfStringPrintf(
"Failed to delete prim \"%s\" from layer \"%s\".",
primPath.GetText(),
layer->GetDisplayName().c_str());
TF_WARN("%s", error.c_str());
throw std::runtime_error(error);
}

// DEBUG: Confirm removal
TF_WARN("DEBUG: Component delete - Successfully removed prim from parent");

layer->RemovePrimIfInert(parent);
}
} else if (!routingEditTarget.IsNull()) {
// NOTE: Need to consider the case of edit routing as well probably

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this a comment you added?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, just as a note for myself when i was first spiking this.. wip

// maybe in the future???
PXR_NS::UsdEditContext ctx(stage, routingEditTarget);

// Note: we allow stronger opinion when editing inside a reference or payload.
Expand Down