Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MAYA-127427 fix rename when staged multiple times #2904

Merged
merged 2 commits into from
Feb 28, 2023
Merged
Show file tree
Hide file tree
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
5 changes: 4 additions & 1 deletion lib/mayaUsd/ufe/UsdSceneItem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,16 @@ UsdSceneItem::create(const Ufe::Path& path, const UsdPrim& prim, int instanceInd
// Ufe::SceneItem overrides
//------------------------------------------------------------------------------

std::string UsdSceneItem::nodeType() const { return fPrim.GetTypeName(); }
std::string UsdSceneItem::nodeType() const { return fPrim ? fPrim.GetTypeName() : std::string(); }

#ifdef UFE_V2_FEATURES_AVAILABLE
std::vector<std::string> UsdSceneItem::ancestorNodeTypes() const
{
std::vector<std::string> strAncestorTypes;

if (!fPrim)
return strAncestorTypes;

#if PXR_VERSION < 2008
static const TfType schemaBaseType = TfType::Find<UsdSchemaBase>();
const TfType schemaType = schemaBaseType.FindDerivedByName(fPrim.GetTypeName().GetString());
Expand Down
6 changes: 3 additions & 3 deletions lib/mayaUsd/ufe/UsdUIInfoHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ bool UsdUIInfoHandler::treeViewCellInfo(const Ufe::SceneItem::Ptr& item, Ufe::Ce
#if !defined(NDEBUG)
assert(usdItem);
#endif
if (usdItem) {
if (usdItem && usdItem->prim()) {
if (!usdItem->prim().IsActive()) {
changed = true;
info.fontStrikeout = true;
Expand Down Expand Up @@ -204,7 +204,7 @@ Ufe::UIInfoHandler::Icon UsdUIInfoHandler::treeViewIcon(const Ufe::SceneItem::Pt

// Check if we have any composition meta data - if yes we display a special badge.
UsdSceneItem::Ptr usdItem = std::dynamic_pointer_cast<UsdSceneItem>(item);
if (usdItem) {
if (usdItem && usdItem->prim()) {
// Variants
if (!usdItem->prim().GetVariantSets().GetNames().empty()) {
icon.badgeIcon = "out_USD_CompArcBadgeV.png";
Expand Down Expand Up @@ -234,7 +234,7 @@ std::string UsdUIInfoHandler::treeViewTooltip(const Ufe::SceneItem::Ptr& item) c
std::string tooltip;

UsdSceneItem::Ptr usdItem = std::dynamic_pointer_cast<UsdSceneItem>(item);
if (usdItem) {
if (usdItem && usdItem->prim()) {
// Composition related metadata.
bool needComma = false;
PXR_NS::SdfReferenceListOp referenceOp;
Expand Down
153 changes: 86 additions & 67 deletions lib/mayaUsd/ufe/UsdUndoRenameCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include "private/UfeNotifGuard.h"
#include "private/Utils.h"

#include <mayaUsd/ufe/Global.h>
#include <mayaUsd/ufe/ProxyShapeHandler.h>
#include <mayaUsd/ufe/Utils.h>
#include <mayaUsd/utils/loadRules.h>
#include <mayaUsdUtils/util.h>
Expand All @@ -32,6 +34,8 @@
#include <pxr/usd/usd/stage.h>

#include <ufe/log.h>
#include <ufe/path.h>
#include <ufe/pathSegment.h>
#include <ufe/scene.h>
#include <ufe/sceneNotification.h>

Expand Down Expand Up @@ -108,61 +112,100 @@ UsdUndoRenameCommand::create(const UsdSceneItem::Ptr& srcItem, const Ufe::PathCo

UsdSceneItem::Ptr UsdUndoRenameCommand::renamedItem() const { return _ufeDstItem; }

bool UsdUndoRenameCommand::renameRedo()
static void sendNotificationToAllStageProxies(
const UsdStagePtr& stage,
const UsdPrim& prim,
const Ufe::Path& srcPath,
const Ufe::Path& dstPath)
{
// If the new name is the same as the current name, do nothing.
// This is the same behavior as the Maya rename command for Maya nodes.
if (_newName.empty())
return true;
const Ufe::Rtid mayaId = getMayaRunTimeId();
for (const std::string& proxyName : ProxyShapeHandler::getAllNames()) {
UsdStagePtr proxyStage = ProxyShapeHandler::dagPathToStage(proxyName);
if (proxyStage != stage)
continue;

// get the stage's default prim path
auto defaultPrimPath = _stage->GetDefaultPrim().GetPath();
const Ufe::PathSegment proxySegment(std::string("|world") + proxyName, mayaId, '|');

const Ufe::PathSegment& srcUsdSegment = srcPath.getSegments()[1];
const Ufe::Path adjustedSrcPath(Ufe::Path::Segments({ proxySegment, srcUsdSegment }));

const Ufe::PathSegment& dstUsdSegment = dstPath.getSegments()[1];
const Ufe::Path adjustedDstPath(Ufe::Path::Segments({ proxySegment, dstUsdSegment }));

UsdSceneItem::Ptr newItem = UsdSceneItem::create(adjustedDstPath, prim);

sendNotification<Ufe::ObjectRename>(newItem, adjustedSrcPath);
}
}

static bool doUsdRename(
const UsdStagePtr& stage,
const UsdPrim& prim,
std::string newName,
const Ufe::Path srcPath,
const Ufe::Path dstPath)
{
// 1- open a changeblock to delay sending notifications.
// 2- update the Internal References paths (if any) first
// 3- set the new name
// Note: during the changeBlock scope we are still working with old items/paths/prims.
// it's only after the scope ends that we start working with new items/paths/prims
SdfChangeBlock changeBlock;

bool status
= MayaUsdUtils::updateReferencedPath(prim, SdfPath(dstPath.getSegments()[1].string()));
if (!status)
return false;

// Make sure the load state of the renamed prim will be preserved.
// We copy all rules that applied to it specifically and remove the rules
// that applied to it specifically.
{
SdfChangeBlock changeBlock;
auto fromPath = SdfPath(srcPath.getSegments()[1].string());
auto destPath = SdfPath(dstPath.getSegments()[1].string());
duplicateLoadRules(*stage, fromPath, destPath);
removeRulesForPath(*stage, fromPath);
}

const UsdPrim& prim = _stage->GetPrimAtPath(_ufeSrcItem->prim().GetPath());
// set the new name
auto primSpec = MayaUsdUtils::getPrimSpecAtEditTarget(prim);
status = primSpec->SetName(newName);
if (!status)
return false;

auto ufeSiblingPath = _ufeSrcItem->path().sibling(Ufe::PathComponent(_newName));
bool status = MayaUsdUtils::updateReferencedPath(
prim, SdfPath(ufeSiblingPath.getSegments()[1].string()));
if (!status) {
return false;
}
return true;
}

// Make sure the load state of the renamed prim will be preserved.
// We copy all rules that applied to it specifically and remove the rules
// that applied to it specifically.
{
auto fromPath = SdfPath(_ufeSrcItem->path().getSegments()[1].string());
auto destPath = SdfPath(ufeSiblingPath.getSegments()[1].string());
duplicateLoadRules(*_stage, fromPath, destPath);
removeRulesForPath(*_stage, fromPath);
}
bool UsdUndoRenameCommand::renameRedo()
{
// If the new name is the same as the current name, do nothing.
// This is the same behavior as the Maya rename command for Maya nodes.
if (_newName.empty())
return true;

// set the new name
auto primSpec = MayaUsdUtils::getPrimSpecAtEditTarget(prim);
status = primSpec->SetName(_newName);
if (!status) {
return false;
}
}
// get the stage's default prim path
auto defaultPrimPath = _stage->GetDefaultPrim().GetPath();

const Ufe::Path srcPath = _ufeSrcItem->path();
const Ufe::Path dstPath = srcPath.sibling(Ufe::PathComponent(_newName));
// Note: must fetch prim again from its path because undo/redo of composite commands
// (or doing multiple undo and then multiple redo) can make the cached prim
// stale.
const UsdPrim prim = _stage->GetPrimAtPath(_ufeSrcItem->prim().GetPath());

if (!doUsdRename(_stage, prim, _newName, srcPath, dstPath))
return false;

// the renamed scene item is a "sibling" of its original name.
_ufeDstItem = createSiblingSceneItem(_ufeSrcItem->path(), _newName);
_ufeDstItem = createSiblingSceneItem(srcPath, _newName);

// update stage's default prim
if (_ufeSrcItem->prim().GetPath() == defaultPrimPath) {
_stage->SetDefaultPrim(_ufeDstItem->prim());
}

// send notification to update UFE data model
sendNotification<Ufe::ObjectRename>(_ufeDstItem, _ufeSrcItem->path());
sendNotificationToAllStageProxies(_stage, prim, srcPath, dstPath);

return true;
}
Expand All @@ -177,40 +220,16 @@ bool UsdUndoRenameCommand::renameUndo()
// get the stage's default prim path
auto defaultPrimPath = _stage->GetDefaultPrim().GetPath();

// 1- open a changeblock to delay sending notifications.
// 2- update the Internal References paths (if any) first
// 3- set the new name
// Note: during the changeBlock scope we are still working with old items/paths/prims.
// it's only after the scope ends that we start working with new items/paths/prims
{
SdfChangeBlock changeBlock;

const UsdPrim& prim = _stage->GetPrimAtPath(_ufeDstItem->prim().GetPath());
const Ufe::Path srcPath = _ufeDstItem->path();
const Ufe::Path dstPath = _ufeSrcItem->path();
// Note: must fetch prim again from its path because undo/redo of composite commands
// (or doing multiple undo and then multiple redo) can make the cached prim
// stale.
const UsdPrim prim = _stage->GetPrimAtPath(_ufeDstItem->prim().GetPath());
const std::string newName = _ufeSrcItem->prim().GetName();

auto ufeSiblingPath
= _ufeSrcItem->path().sibling(Ufe::PathComponent(_ufeSrcItem->prim().GetName()));
bool status = MayaUsdUtils::updateReferencedPath(
prim, SdfPath(ufeSiblingPath.getSegments()[1].string()));
if (!status) {
return false;
}

// Make sure the load state of the renamed prim will be preserved.
// We copy all rules that applied to it specifically and remove the rules
// that applied to it specifically.
{
auto fromPath = SdfPath(_ufeDstItem->path().getSegments()[1].string());
auto destPath = SdfPath(ufeSiblingPath.getSegments()[1].string());
duplicateLoadRules(*_stage, fromPath, destPath);
removeRulesForPath(*_stage, fromPath);
}

auto primSpec = MayaUsdUtils::getPrimSpecAtEditTarget(prim);
status = primSpec->SetName(_ufeSrcItem->prim().GetName());
if (!status) {
return false;
}
}
if (!doUsdRename(_stage, prim, newName, srcPath, dstPath))
return false;

// the renamed scene item is a "sibling" of its original name.
_ufeSrcItem = createSiblingSceneItem(_ufeDstItem->path(), _ufeSrcItem->prim().GetName());
Expand All @@ -221,7 +240,7 @@ bool UsdUndoRenameCommand::renameUndo()
}

// send notification to update UFE data model
sendNotification<Ufe::ObjectRename>(_ufeSrcItem, _ufeDstItem->path());
sendNotificationToAllStageProxies(_stage, prim, srcPath, dstPath);

return true;
}
Expand Down