From ef1216a13c82731bda5a27e11db85abb3afb5f26 Mon Sep 17 00:00:00 2001 From: Pierre Tremblay Date: Tue, 15 Nov 2022 11:43:58 -0500 Subject: [PATCH] Test if visibility edit is valid before returning command. --- lib/mayaUsd/ufe/UsdUndoVisibleCommand.cpp | 26 +++-- lib/mayaUsd/ufe/UsdUndoVisibleCommand.h | 6 +- test/lib/ufe/testVisibilityCmd.py | 110 ++++++++++++++-------- 3 files changed, 96 insertions(+), 46 deletions(-) diff --git a/lib/mayaUsd/ufe/UsdUndoVisibleCommand.cpp b/lib/mayaUsd/ufe/UsdUndoVisibleCommand.cpp index 8ec1b1c775..ada9bf236b 100644 --- a/lib/mayaUsd/ufe/UsdUndoVisibleCommand.cpp +++ b/lib/mayaUsd/ufe/UsdUndoVisibleCommand.cpp @@ -24,11 +24,14 @@ namespace MAYAUSD_NS_DEF { namespace ufe { -UsdUndoVisibleCommand::UsdUndoVisibleCommand(const UsdPrim& prim, bool vis) +UsdUndoVisibleCommand::UsdUndoVisibleCommand( + const UsdPrim& prim, + bool vis, + const PXR_NS::SdfLayerHandle& layer) : Ufe::UndoableCommand() , _prim(prim) , _visible(vis) - , _layer(getEditRouterLayer(PXR_NS::TfToken("visibility"), prim)) + , _layer(layer) { } @@ -39,19 +42,26 @@ UsdUndoVisibleCommand::Ptr UsdUndoVisibleCommand::create(const UsdPrim& prim, bo if (!prim) { return nullptr; } - return std::make_shared(prim, vis); -} -void UsdUndoVisibleCommand::execute() -{ - UsdGeomImageable primImageable(_prim); + auto layer = getEditRouterLayer(PXR_NS::TfToken("visibility"), prim); + + UsdGeomImageable primImageable(prim); + + EditTargetGuard guard(prim, layer); std::string errMsg; if (!MayaUsd::ufe::isAttributeEditAllowed(primImageable.GetVisibilityAttr(), &errMsg)) { MGlobal::displayError(errMsg.c_str()); - return; + return nullptr; } + return std::make_shared(prim, vis, layer); +} + +void UsdUndoVisibleCommand::execute() +{ + UsdGeomImageable primImageable(_prim); + UsdUndoBlock undoBlock(&_undoableItem); EditTargetGuard guard(_prim, _layer); diff --git a/lib/mayaUsd/ufe/UsdUndoVisibleCommand.h b/lib/mayaUsd/ufe/UsdUndoVisibleCommand.h index 4bc2e160cb..79e2f73be9 100644 --- a/lib/mayaUsd/ufe/UsdUndoVisibleCommand.h +++ b/lib/mayaUsd/ufe/UsdUndoVisibleCommand.h @@ -31,7 +31,11 @@ class MAYAUSD_CORE_PUBLIC UsdUndoVisibleCommand : public Ufe::UndoableCommand public: typedef std::shared_ptr Ptr; - UsdUndoVisibleCommand(const PXR_NS::UsdPrim& prim, bool vis); + // Public for std::make_shared() access, use create() instead. + UsdUndoVisibleCommand( + const PXR_NS::UsdPrim& prim, + bool vis, + const PXR_NS::SdfLayerHandle& layer); ~UsdUndoVisibleCommand() override; // Delete the copy/move constructors assignment operators. diff --git a/test/lib/ufe/testVisibilityCmd.py b/test/lib/ufe/testVisibilityCmd.py index 18444b7564..33f4683d9e 100644 --- a/test/lib/ufe/testVisibilityCmd.py +++ b/test/lib/ufe/testVisibilityCmd.py @@ -20,7 +20,7 @@ def getSessionLayer(context, routingData): if prim is None: print('Prim not in context') return - + routingData['layer'] = prim.GetStage().GetSessionLayer().identifier def createUfePathSegment(usdPath): @@ -34,86 +34,122 @@ def createUfePathSegment(usdPath): return ufe.PathSegment(usdPath, mayaUsd.ufe.getUsdRunTimeId(), '/') class VisibilityCmdTestCase(unittest.TestCase): - '''Verify the Maya Edit Router for visibility.''' - pluginsLoaded = False - - @classmethod - def setUpClass(cls): + '''Verify the Maya Edit Router for visibility.''' + pluginsLoaded = False + + @classmethod + def setUpClass(cls): fixturesUtils.readOnlySetUpClass(__file__, loadPlugin=False) if not cls.pluginsLoaded: cls.pluginsLoaded = mayaUtils.isMayaUsdPluginLoaded() - - @classmethod - def tearDownClass(cls): + + @classmethod + def tearDownClass(cls): standalone.uninitialize() - - def setUp(self): - ''' Called initially to set up the Maya test environment ''' - # Load plugins - self.assertTrue(self.pluginsLoaded) - cmds.select(clear=True) - def testEditRouter(self): - '''Test edit router functionality.''' + def setUp(self): + self.assertTrue(self.pluginsLoaded) cmds.file(new=True, force=True) import mayaUsd_createStageWithNewLayer - + # Create the following hierarchy: # # ps # |_ A # |_ B # - + psPathStr = mayaUsd_createStageWithNewLayer.createStageWithNewLayer() stage = mayaUsd.lib.GetPrim(psPathStr).GetStage() stage.DefinePrim('/A', 'Xform') stage.DefinePrim('/B', 'Xform') - + psPath = ufe.PathString.path(psPathStr) psPathSegment = psPath.segments[0] aPath = ufe.Path([psPathSegment, usdUtils.createUfePathSegment('/A')]) bPath = ufe.Path([psPathSegment, usdUtils.createUfePathSegment('/B')]) - a = ufe.Hierarchy.createItem(aPath) - b = ufe.Hierarchy.createItem(bPath) + self.a = ufe.Hierarchy.createItem(aPath) + self.b = ufe.Hierarchy.createItem(bPath) + + cmds.select(clear=True) + + def tearDown(self): + # Restore default edit router. + mayaUsd.lib.restoreDefaultEditRouter('visibility') + + def _testEditRouter(self): + '''Test edit router functionality.''' # Select /A sn = ufe.GlobalSelection.get() sn.clear() - sn.append(a) - - # Hide A - cmds.hide() - + sn.append(self.a) + # Get the session layer prim = mayaUsd.ufe.ufePathToPrim("|stage1|stageShape1,/A") sessionLayer = prim.GetStage().GetSessionLayer() - + # Check that the session layer is empty self.assertTrue(sessionLayer.empty) - - # Register visibility + + # Send visibility edits to the session layer. mayaUsd.lib.registerEditRouter('visibility', getSessionLayer) + + # Check that something was written to the session layer + self.assertIsNotNone(sessionLayer) # Select /B sn = ufe.GlobalSelection.get() sn.clear() - sn.append(b) - + sn.append(self.b) + # Hide B cmds.hide() - + # Check that something was written to the session layer self.assertIsNotNone(sessionLayer) self.assertIsNotNone(sessionLayer.GetPrimAtPath('/B')) - + # Check that any visibility changes were written to the session layer self.assertIsNotNone(sessionLayer.GetAttributeAtPath('/B.visibility').default) - + # Check that correct visibility changes were written to the session layer self.assertEqual(filterUsdStr(sessionLayer.ExportToString()), - 'over "B"\n{\n token visibility = "invisible"\n}') + 'over "B"\n{\n token visibility = "invisible"\n}') + + def testEditRouterShowHideMultipleSelection(self): + '''Test edit routing under show and hide scenarios with multiple selection.''' + + # Get the session layer, check it's empty. + prim = mayaUsd.ufe.ufePathToPrim("|stage1|stageShape1,/A") + sessionLayer = prim.GetStage().GetSessionLayer() + self.assertTrue(sessionLayer.empty) + + # Send visibility edits to the session layer. + mayaUsd.lib.registerEditRouter('visibility', getSessionLayer) + + # Select /A, hide it. + sn = ufe.GlobalSelection.get() + sn.clear() + sn.append(self.a) + + cmds.hide() + + # Check visibility was written to the session layer. + self.assertEqual(filterUsdStr(sessionLayer.ExportToString()), + 'over "A"\n{\n token visibility = "invisible"\n}') + + # Hiding a multiple selection with already-hidden A must not error. + # Careful: hide command clears the selection, so must add /A again. + sn.append(self.a) + sn.append(self.b) + + cmds.hide() + + # Check visibility was written to the session layer. + self.assertEqual(filterUsdStr(sessionLayer.ExportToString()), + 'over "A"\n{\n token visibility = "invisible"\n}\nover "B"\n{\n token visibility = "invisible"\n}') if __name__ == '__main__': - unittest.main(verbosity=2) + unittest.main(verbosity=2)