-
Notifications
You must be signed in to change notification settings - Fork 201
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-104215: improve renaming restriction on prim objects #475
MAYA-104215: improve renaming restriction on prim objects #475
Conversation
…arget layer errors out: Unable to rename [object name] on current target layer, please set [Layername] as target layer to proceed.
prim.GetName().GetString(), | ||
possibleTargetLayer->GetDisplayName()); | ||
throw std::runtime_error(err.c_str()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We check here if the target layer has any opinions that affects selected prim. If it doesn't pass the check, we then find the possible target layer and append it's display name to the error message. Finally we throw a runtime_error message.
UsdSceneItem::Ptr m_fUfeSrcItem; | ||
SdfPath m_fUsdSrcPath; | ||
UsdSceneItem::Ptr m_fUfeDstItem; | ||
SdfPath m_fUsdDstPath; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Following the C++ guideline, member variables need to be prefixed with m_
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, we use _
prefix - see https://github.com/Autodesk/maya-usd/blob/dev/doc/codingGuidelines.md#naming-file-type-variable-constant-function-namespace-macro-template-parameters-schema-names
New modules should start using these guidelines, but we still have to plan how to adapt the existing code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My bad, I was sill thinking about "m_" :) Fixed in 54166d2
@@ -109,8 +109,6 @@ SdfLayerHandle defPrimSpecLayer(const UsdPrim& prim) | |||
|
|||
SdfLayerHandle defLayer; | |||
auto layerStack = prim.GetStage()->GetLayerStack(); | |||
auto stage = prim.GetStage(); | |||
auto primFromPath = stage->GetPrimAtPath(prim.GetPath()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove unused variables.
lib/mayaUsd/ufe/Utils.cpp
Outdated
} | ||
|
||
return true; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To find out if a specific layer contains any opinions that affect a particular prim, we can use the Sdf's GetPrimAtPath() for that prim. If the primSpec result returns nothing that means the target layer doesn't contain any opinions on a particular prim.
lib/mayaUsd/ufe/Utils.cpp
Outdated
} | ||
return targetLayer; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is used to give the user a hint to what target layer to set in order to rename a particular prim.
lib/mayaUsd/ufe/Utils.cpp
Outdated
@@ -124,6 +122,38 @@ SdfLayerHandle defPrimSpecLayer(const UsdPrim& prim) | |||
return defLayer; | |||
} | |||
|
|||
bool isTargetLayerHaveOpinion(const UsdPrim& prim) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would read better as
doesTargetLayerHaveOpinion()
or just plain
targetLayerHasOpinion()
(shorter is often better).
lib/mayaUsd/ufe/Utils.cpp
Outdated
|
||
// to know whether the target layer contains any opinions that | ||
// affect a particular prim, there must be a primSpec for that prim | ||
if (!primSpec) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit-pick: if SdfPrimSpec supports an
explicit operator bool()
(looks like it does, but couldn't find it)
could be
return bool(primSpec);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point @ppt-adsk but I don't find any "explicit operator bool" both in SdfSpec and SdfPrimSpec
lib/mayaUsd/ufe/Utils.cpp
Outdated
return true; | ||
} | ||
|
||
SdfLayerHandle targetLayerWithOpion(const UsdPrim& prim) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: "Opion" --> "Opinion".
Also, isn't it the case that this will return the highest-priority layer that has an opinion, either def or over? It would be good if the function would say that, e.g.
SdfLayerHandle strongestLayerWithOpinion(const UsdPrim& prim)
or
SdfLayerHandle strongestLayerWithPrimSpec(const UsdPrim& prim)
A minor point is that the existing function in the Utils file is called defPrimSpecLayer, i.e. uses "prim spec" rather than "opinion". Perhaps we should standardize on one terminology or the other.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please see 54166d2
I agree with standardization on one terminology, I picked "prim spec" instead of "opinion" for now.
Regarding the function names, I made following changes and dropped the target. Let me know if this reads better:
Before:
isTargetLayerHaveOpinion
targetLayerWithOpion
After:
doesLayerHavePrimSpec
strongestLayerWithPrimSpec
lib/mayaUsd/ufe/Utils.h
Outdated
@@ -56,6 +56,14 @@ bool isRootChild(const Ufe::Path& path); | |||
MAYAUSD_CORE_PUBLIC | |||
SdfLayerHandle defPrimSpecLayer(const UsdPrim& prim); | |||
|
|||
//! Check if the target layer has any opinions that affects a particular prim | |||
MAYAUSD_CORE_PUBLIC | |||
bool isTargetLayerHaveOpinion(const UsdPrim& prim); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel the naming of these two functions is confusing, because they both talk about "target layer", but they're not related.
"isTargetLayerHaveOpinion" is really answering the question: does the edit target layer on the prim's stage have an opinion?
"targetLayerWithOpion" [sic] is answering the question: what is the strongest layer that has an opinion for this prim? From the point of view of this function, there is no target involved, and therefore I would remove the word "target" here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please see 54166d2
I agree. I made following changes and dropped the target. Let me know if this reads better:
Before:
isTargetLayerHaveOpinion
After:
doesLayerHavePrimSpec
"doesLayerHavePrimSpec" answers this question: Does the layer that you are currently on have any primSpec (a.k.a opinion) on the selected prim?
std::string err = TfStringPrintf("No prim found at %s", prim.GetPath().GetString().c_str()); | ||
throw std::runtime_error(err.c_str()); | ||
} | ||
|
||
// check if the target layer has any opinions that affects selected prim | ||
if (!isTargetLayerHaveOpinion(prim)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So here if the edit target doesn't have an opinion, we tell the user to set the edit target to the strongest layer than does have an opinion. O.K., maybe that makes sense, even if the strongest layer only has "over" opinion.
But what if the edit target is on a weak layer and the weak layer DOES have an opinion, that is overridden by an opinion in a stronger layer? We're saying that's O.K.? The user will rename in the weak layer, but the stronger layer will still have its opinion and it will be composed into the final result, no? That doesn't seem to meet Will's acceptance criteria that "Trying to rename an object with opinions on stronger layers error out." Perhaps what you're showing here is really work in progress and you're going to fix this? Or is there something I haven't understood?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very valid question and I should have elaborated more on the change here:
if (!MayaUsdUtils::doesLayerHavePrimSpec(prim)) solves this request:
Trying to rename an object that was not defined on the target layer errors out
but as you also mentioned it doesn't really solve this request:
Trying to rename an object with opinions on stronger layers error out.
I am working on addressing this as we speak.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- renamed usd utility functions related to "usd" and "sdf" operations - moved usd utility functions from mayaUsd\ufe\Utils.h to usd\utils\util.h under MayaUsdUtils namespace. - cleaned up variable names according to c++ guideline.
lib/usd/utils/util.cpp
Outdated
} | ||
|
||
SdfLayerHandle | ||
MayaUsdUtils::strongestLayerWithPrimSpec(const UsdPrim& prim) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extra MayaUsdUtils:: in line 64 and 48 was added by accident. I will fix this in the next PR.
Error if object to rename has ANY definitions or overs on ANY stronger or weaker layers. This is the most restrictive we can be. We will revisit how much we loosen this up later. Cannot rename a prim with definitions or opinions on other layers. Opinions exist in [layer name 1], [layer name 2], [layer name 3], [layer name 4],etc...”
lib/usd/utils/util.cpp
Outdated
} | ||
|
||
std::vector<SdfLayerHandle> | ||
layersWithOpinion(const UsdPrim& prim) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Naming: the other functions in this translation units use primSpec, this one should as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please see 4c67b69
lib/usd/utils/util.cpp
Outdated
// ordered from strongest to weakest opinion. | ||
const auto& primStack = prim.GetPrimStack(); | ||
|
||
std::vector<SdfLayerHandle> layersWithOpion; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: "layersWithOpion" --> "layersWithOpinion", but of course if you rename to primSpec this will disappear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see 4c67b69
Some how I can't type opinion
properly :)
lib/usd/utils/util.cpp
Outdated
} | ||
|
||
bool | ||
doesLayerHavePrimSpec(const UsdPrim& prim) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the naming would be much clearer as
doesEditTargetLayerHavePrimSpec()
I know it's wordy, maybe you can do better, but this name (or a similar name) tells you which layer we're talking about, the edit target layer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, I like your suggested name.
see 4c67b69
lib/usd/utils/util.h
Outdated
MAYA_USD_UTILS_PUBLIC | ||
bool doesLayerHavePrimSpec(const UsdPrim&); | ||
|
||
//! Return the layer that has any opinions on a particular prim |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be clearer as
"Return the strongest layer that has an opinion on the argument prim."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see 4c67b69
_ufeSrcItem = srcItem; | ||
_usdSrcPath = prim.GetPath(); | ||
|
||
// Every call to rename() (through execute(), undo() or redo()) removes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit-pick: indentation changed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see 4c67b69
std::string err = TfStringPrintf("No prim found at %s", prim.GetPath().GetString().c_str()); | ||
throw std::runtime_error(err.c_str()); | ||
} | ||
|
||
// if the current layer doesn't have any opinions that affects selected prim | ||
if (!MayaUsdUtils::doesLayerHavePrimSpec(prim)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this just _layer != theEditTargetLayer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. Correct, we could also use _layer != prim.GetStage()->GetEditTarget().GetLayer()
instead. I keep using doesEditTargetLayerHavePrimSpec which is a bit more generic. Hope this is Ok.
for (auto layer : layers) { | ||
layerNames.append("[" + layer->GetDisplayName() + "]" + ","); | ||
} | ||
layerNames.pop_back(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why omit the last layer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see 4c67b69
I rename layerNames
to layerDisplayNames
so it reads better.
I am not omitting any layers and rather the extra "," at the end of layerDisplayNames
string.
This is the message the design wants to show up as part of the error message:
Opinions exist in [layer name 1], [layer name 2], [layer name 3], [layer name 4].”
So when I iterate through the layers, I get their GetDisplayName and concatenate them in the
layerDisplayNames string separated by ","
for (auto layer : layers) {
layerDisplayNames.append("[" + layer->GetDisplayName() + "]" + ",");
}
layerDisplayNames.pop_back();
There are better ways of doing this, but this is one way I did.
- edited code logics in testRename to use usdCylinder.ma scene since with new rename restrictions top_layer.ma doesn't meet the requirements for testing undo/redo - refactored code around opening maya test scenes and introduced three utility functions (openCylinderScene, openTwoSpheresScene, openSphereAnimatedRadiusScene)
# expect the exception happens | ||
with self.assertRaises(RuntimeError): | ||
newName = 'Ball_35_Renamed' | ||
cmds.rename(newName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ppt-adsk I added two test cases for rename restriction operations:
testRenameRestriction
is to test if the prim that we are about to rename is in the correct layer
testRenameRestriction2
is to test if the prim that we are about to rename doesn't have any definitions or opinions on other layers.
If you think testRenameRestriction2
is ugly, I am happy to change it with something more meaningful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost there! Minor tweak to just rename the test functions, and we're all done.
test/lib/ufe/testRename.py
Outdated
self.assertEqual(len(propsChildren), len(propsChildrenPre)) | ||
|
||
def testRenameRestriction(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about "testRenameRestrictionSameLayerDef", or similar?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test/lib/ufe/testRename.py
Outdated
newName = 'Ball_35_Renamed' | ||
cmds.rename(newName) | ||
|
||
def testRenameRestriction2(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about "testRenameRestrictionOtherLayerOpinions", or similar?
Great job Hamed! |
tbb\concurrent_vector.h(177): fatal error C1017: invalid integer constant expression
|
||
Ufe::ObjectRename notification(_ufeDstItem, ufeSrcPath); | ||
Ufe::Scene::notifyObjectPathChange(notification); | ||
sendRenameNotification(_ufeDstItem, _ufeSrcItem->path()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor refactoring here.
{ | ||
UsdEditContext ctx(_stage, _layer); | ||
status = _stage->RemovePrim(_ufeSrcItem->prim().GetPath()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the new restriction in place it is now safe to remove the prim from the scene graph rather than deactivating it.When RemovePrim is called, I simply pass the _ufeSrcItem->prim().GetPath()
rather than creating a new srcPrim which would be really unnecessary.
Redo operation:
1- Call SdfCopySpec to copy ALL the child specs from _usdSrcPath to _usdDstPath. This is a crucial call.
2- Remove the prim at _ufeSrcItem USD path.
3- set _ufeDstItem by calling createSiblingSceneItem
4- send rename notification
UsdSceneItem::Ptr _ufeDstItem; | ||
SdfPath _usdDstPath; | ||
UsdSceneItem::Ptr _ufeDstItem; | ||
SdfPath _usdDstPath; | ||
|
||
}; // UsdUndoRenameCommand | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have converted tabs to dots. If you find them distracting, Github allow hiding whitespace changes during review:
Please see
https://medium.com/@kevinpmcc/hide-whitespace-for-easier-github-code-reviews-d3f476d03863
@ppt-adsk Ah....... I am starting to think why we need to rely on I honestly think we can simply rename a prim in place. I just realized that https://graphics.pixar.com/usd/docs/api/class_sdf_prim_spec.html#aa1f241d28f26488867a276eca6d54405 This would really simplify a lot of things. Stay tuned..... |
This change simplifies the rename operation by simply renaming a prim in place via SdfPrimSpec's SetName routine and removes the old work-flow involving SdfCopySpec.
…operations in undo/redo. - To read the code better, I added a new member variable _oldName that holds the prim's original name.
…sd file for testing purposes. - Renamed testRename to testRenameUndo - Added new logics for testing new way of renaming a prim name via SdfPrimSpec.
…s around the stage behavior that deserves an explanation.
- Add a simple testRenameRestrictionExternalReference unit test.
…ternal reference and create a new utility for it.
… we do still want the opinion detection in other layers happens.
…things more readable. - change the container type for layersWithContribution method from std::vector to std::set to guarantee having unique layers.
…me_logics Improve rename logics
…ved from the prim argument.
// SdfLayer is a "simple" container, and all it knows about defaultPrim is that it is a piece of token-valued layer metadata. | ||
// It is only the higher-level Usd and Pcp modules that know that it is identifying a prim on the stage. | ||
// One must use the SdfLayer API for setting the defaultPrim when you rename the prim it identifies. | ||
if(primNameStr == stageDefPrimNameStr){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ppt-adsk We don't need to do a comparison here. if(!stageDefPrimNameStr.empty()) does the work. Will fix it in the next commit,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I don't think that would work now that I think about it. please ignore my last comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
…"Question around SdfPrimSepc's SetName routine" thread.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just that minor out of date comment to remove, but otherwise looks good to me!
// MAYA-92264: Pixar bug prevents undo from working. Try again with USD | ||
// version 0.8.5 or later. PPT, 7-Jul-2018. | ||
try { | ||
// MAYA-92264: Pixar bug prevents undo from working. Try again with USD |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment is no longer valid, right?
PR Changes:
This PR brings new improvements to rename command and adds new restrictions:
lib\usd\utils\util.h
Unit tests:
testRename
is renamed totestRenameUndo
.