diff --git a/lib/mayaUsd/commands/Readme.md b/lib/mayaUsd/commands/Readme.md index 54939309f3..7e60a3bdd2 100644 --- a/lib/mayaUsd/commands/Readme.md +++ b/lib/mayaUsd/commands/Readme.md @@ -633,7 +633,7 @@ The purpose of this command is edit layers. | `-addAnonymous` | `-aa` | string | Add an anonynous layer at the top of the stack, returns it | | `-insertSubPath` | `-is` | int string | Insert a sub layer path at a given index | | `-muteLayer` | `-mt` | bool string | Mute or unmute the named layer | -| `-lockLayer` | `-lk` | int string | Lock, System-Lock or unlock a layer. `0` = Unlocked, `1` = Locked and `2` = System-Locked | +| `-lockLayer` | `-lk` | int int string | Lock, System-Lock or unlock a layer and its sublayers. `Lock Type`: `0` = Unlocked, `1` = Locked and `2` = System-Locked. `Include Sublayers` : `0` = Top Layer Only, `1` : Top and Sublayers | | `-refreshSystemLock`| `-rl` | string int | Refreshes the lock status of the named layer. `0` = Only top layer, `1` = Include the sublayers| | `-replaceSubPath` | `-rp` | string string | Replaces a path in the layer stack | | `-removeSubPath` | `-rs` | int string | Remove a sub layer at a given index | @@ -655,6 +655,7 @@ The purpose of this command is to control the layer editor window. | `-removeSubLayer` | `-rs` | Remove sub-layers | | `-clearLayer` | `-cl` | Erase everything in a layer | | `-discardEdits` | `-de` | Discard changes made on a layer | +| `-layerHasSubLayers` | `-ll` | Query if the layer has sub-layers | | `-isAnonymousLayer` | `-al` | Query if the layer is anonymous | | `-isLayerDirty` | `-dl` | Query if the layer has been modified | | `-isInvalidLayer` | `-il` | Query if the layer is not found or invalid | @@ -668,7 +669,8 @@ The purpose of this command is to control the layer editor window. | `-layerIsLocked` | `-lo` | Query if the layer itself is locked | | `-layerAppearsSystemLocked` | `-as` | Query if the layer's parent is system-locked | | `-layerIsSystemLocked` | `-ls` | Query if the layer itself is system-locked | -| `-lockLayer` | `-lk` | Lock, System-Lock or unlock a layer. `0` = Unlocked, `1` = Locked and `2` = System-Locked | +| `-lockLayer` | `-lk` | Lock or unlock a layer. | +| `-lockLayerAndSubLayers`| `-la` | Lock or unlocks a layer and its sublayers. | | `-layerNeedsSaving` | `-ns` | Query if the layer is dirty or anonymous | | `-printLayer` | `-pl` | Print the layer to the script editor output | | `-proxyShape` | `-ps` | Query the proxyShape path or sets the selected shape by its path. Takes the path as argument | diff --git a/lib/mayaUsd/commands/abstractLayerEditorWindow.h b/lib/mayaUsd/commands/abstractLayerEditorWindow.h index f97613168c..0cf95c1039 100644 --- a/lib/mayaUsd/commands/abstractLayerEditorWindow.h +++ b/lib/mayaUsd/commands/abstractLayerEditorWindow.h @@ -88,6 +88,7 @@ class MAYAUSD_CORE_PUBLIC AbstractLayerEditorWindow virtual bool layerAppearsSystemLocked() = 0; virtual bool layerIsSystemLocked() = 0; virtual bool layerIsReadOnly() = 0; + virtual bool layerHasSubLayers() = 0; virtual std::string proxyShapeName() const = 0; virtual void removeSubLayer() = 0; @@ -102,6 +103,7 @@ class MAYAUSD_CORE_PUBLIC AbstractLayerEditorWindow virtual void selectPrimsWithSpec() = 0; virtual void updateLayerModel() = 0; virtual void lockLayer() = 0; + virtual void lockLayerAndSubLayers() = 0; virtual void selectProxyShape(const char* shapePath) = 0; }; diff --git a/lib/mayaUsd/commands/layerEditorCommand.cpp b/lib/mayaUsd/commands/layerEditorCommand.cpp index 4509b2136a..a3c5c382b7 100644 --- a/lib/mayaUsd/commands/layerEditorCommand.cpp +++ b/lib/mayaUsd/commands/layerEditorCommand.cpp @@ -798,18 +798,32 @@ class LockLayer : public BaseCmd if (!stage) return false; - if (_systemLock) { - saveSelection(); - MayaUsd::lockLayer( - _proxyShapePath, layer, MayaUsd::LayerLockType::LayerLock_SystemLocked, true); - } else if (_lockIt) { - saveSelection(); - MayaUsd::lockLayer( - _proxyShapePath, layer, MayaUsd::LayerLockType::LayerLock_Locked, true); + saveSelection(); + + std::set layersToUpdate; + if (_includeSublayers) { + // If _includeSublayers is True, we attempt to refresh the system lock status of all + // layers under the given layer. This is specially useful when reloading a stage. + bool includeTopLayer = true; + layersToUpdate = MayaUsd::getAllSublayerRefs(layer, includeTopLayer); } else { - saveSelection(); - MayaUsd::lockLayer( - _proxyShapePath, layer, MayaUsd::LayerLockType::LayerLock_Unlocked, true); + layersToUpdate.insert(layer); + } + + for (auto layerIt : layersToUpdate) { + if (MayaUsd::isLayerLocked(layerIt)) { + _previousStates.push_back(MayaUsd::LayerLockType::LayerLock_Locked); + } else if (MayaUsd::isLayerSystemLocked(layerIt)) { + _previousStates.push_back(MayaUsd::LayerLockType::LayerLock_SystemLocked); + } else { + _previousStates.push_back(MayaUsd::LayerLockType::LayerLock_Unlocked); + } + _layers.push_back(layerIt); + } + + // Execute lock commands + for (size_t layerIndex = 0; layerIndex < _layers.size(); layerIndex++) { + MayaUsd::lockLayer(_proxyShapePath, _layers[layerIndex], _lockType, true); } return true; @@ -820,19 +834,32 @@ class LockLayer : public BaseCmd auto stage = getStage(); if (!stage) return false; - // Note: the undo of both lock and system-lock are unlock by design. - if (_systemLock || _lockIt) { - MayaUsd::lockLayer( - _proxyShapePath, layer, MayaUsd::LayerLockType::LayerLock_Unlocked, true); - restoreSelection(); + + if (_layers.size() != _previousStates.size()) { + return false; + } + // Execute lock commands + for (size_t layerIndex = 0; layerIndex < _layers.size(); layerIndex++) { + // Note: the undo of system-locked is unlocked by design. + if (_previousStates[layerIndex] == MayaUsd::LayerLockType::LayerLock_SystemLocked) { + MayaUsd::lockLayer( + _proxyShapePath, + _layers[layerIndex], + MayaUsd::LayerLockType::LayerLock_Unlocked, + true); + } else { + MayaUsd::lockLayer( + _proxyShapePath, _layers[layerIndex], _previousStates[layerIndex], true); + } } + restoreSelection(); return true; } - std::string _proxyShapePath; - bool _lockIt = true; - bool _systemLock = false; + MayaUsd::LayerLockType _lockType = MayaUsd::LayerLockType::LayerLock_Locked; + bool _includeSublayers = false; + std::string _proxyShapePath; private: UsdStageWeakPtr getStage() @@ -871,7 +898,9 @@ class LockLayer : public BaseCmd globalSn->replaceWith(UsdUfe::recreateDescendants(_savedSn, path)); } - Ufe::Selection _savedSn; + Ufe::Selection _savedSn; + std::vector _previousStates; + SdfLayerHandleVector _layers; }; class RefreshSystemLockLayer : public BaseCmd @@ -901,15 +930,33 @@ class RefreshSystemLockLayer : public BaseCmd _refreshLayerSystemLock(layer); } + // Execute lock commands + for (size_t layerIndex = 0; layerIndex < _layers.size(); layerIndex++) { + if (!_lockCommands[layerIndex]->doIt(_layers[layerIndex])) { + return false; + } + } + return true; } // The command itself doesn't retain its state. However, the underlying logic contains commands // that are undoable. - bool undoIt(SdfLayerHandle layer) override { return true; } + bool undoIt(SdfLayerHandle layer) override + { + // Execute lock commands + for (size_t layerIndex = 0; layerIndex < _layers.size(); layerIndex++) { + if (!_lockCommands[layerIndex]->undoIt(_layers[layerIndex])) { + return false; + } + } + return true; + } - std::string _proxyShapePath; - bool _refreshSubLayers = false; + std::string _proxyShapePath; + bool _refreshSubLayers = false; + std::vector> _lockCommands; + SdfLayerHandleVector _layers; private: std::string _quote(const std::string& string) @@ -917,8 +964,8 @@ class RefreshSystemLockLayer : public BaseCmd return std::string(" \"") + string + std::string("\""); } - // Checks if the file layer or its sublayers are accessible on disk, and updates the system-lock - // status. + // Checks if the file layer or its sublayers are accessible on disk, and adds the layer + // to _layers along with the _lockCommands to updates the system-lock status. void _refreshLayerSystemLock(SdfLayerHandle usdLayer) { // Anonymous layers do not need to be checked. @@ -938,27 +985,35 @@ class RefreshSystemLockLayer : public BaseCmd if (result[0] == 1 && MayaUsd::isLayerSystemLocked(usdLayer)) { // If the file has write permissions and the layer is currently // system-locked: Unlock the layer - _lockLayer(usdLayer, MayaUsd::LayerLockType::LayerLock_Unlocked); + + // Create the lock command + auto cmd = std::make_shared(); + cmd->_lockType = MayaUsd::LayerLockType::LayerLock_Unlocked; + cmd->_includeSublayers = false; + cmd->_proxyShapePath = _proxyShapePath; + + // Add the lock command and its parameter to be executed + _lockCommands.push_back(std::move(cmd)); + _layers.push_back(usdLayer); } else if (result[0] == 0 && !MayaUsd::isLayerSystemLocked(usdLayer)) { // If the file doesn't have write permissions and the layer is currently not // system-locked: System-lock the layer - _lockLayer(usdLayer, MayaUsd::LayerLockType::LayerLock_SystemLocked); + + // Create the lock command + auto cmd = std::make_shared(); + cmd->_lockType = MayaUsd::LayerLockType::LayerLock_SystemLocked; + cmd->_includeSublayers = false; + cmd->_proxyShapePath = _proxyShapePath; + + // Add the lock command and its parameter to be executed + _lockCommands.push_back(std::move(cmd)); + _layers.push_back(usdLayer); } } } } } - void _lockLayer(SdfLayerHandle usdLayer, MayaUsd::LayerLockType lockState) - { - std::string cmd; - cmd = "mayaUsdLayerEditor -edit -lockLayer "; - cmd += std::to_string(lockState); - cmd += _quote(_proxyShapePath.c_str()); - cmd += _quote(usdLayer->GetIdentifier()); - MGlobal::executeCommand(MString(cmd.c_str()), /*display*/ true, /*undo*/ true); - } - UsdStageWeakPtr getStage() { auto prim = UsdMayaQuery::GetPrim(_proxyShapePath.c_str()); @@ -1057,7 +1112,8 @@ MSyntax LayerEditorCommand::createSyntax() syntax.makeFlagMultiUse(kAddAnonSublayerFlag); // parameter: proxy shape name syntax.addFlag(kMuteLayerFlag, kMuteLayerFlagL, MSyntax::kBoolean, MSyntax::kString); - syntax.addFlag(kLockLayerFlag, kLockLayerFlagL, MSyntax::kLong, MSyntax::kString); + syntax.addFlag( + kLockLayerFlag, kLockLayerFlagL, MSyntax::kLong, MSyntax::kBoolean, MSyntax::kString); // parameter 1: proxy shape name // parameter 2: refresh sub layers syntax.addFlag( @@ -1209,8 +1265,11 @@ MStatus LayerEditorCommand::parseArgs(const MArgList& argList) // 2 = SystemLocked argParser.getFlagArgument(kLockLayerFlag, 0, lockValue); + bool includeSublayers = false; + argParser.getFlagArgument(kLockLayerFlag, 1, includeSublayers); + MString proxyShapeName; - argParser.getFlagArgument(kLockLayerFlag, 1, proxyShapeName); + argParser.getFlagArgument(kLockLayerFlag, 2, proxyShapeName); auto prim = UsdMayaQuery::GetPrim(proxyShapeName.asChar()); if (prim == UsdPrim()) { @@ -1220,8 +1279,21 @@ MStatus LayerEditorCommand::parseArgs(const MArgList& argList) } auto cmd = std::make_shared(); - cmd->_lockIt = lockValue == 1 ? true : false; - cmd->_systemLock = lockValue == 2 ? true : false; + switch (lockValue) { + case 1: { + cmd->_lockType = MayaUsd::LayerLockType::LayerLock_Locked; + break; + } + case 2: { + cmd->_lockType = MayaUsd::LayerLockType::LayerLock_SystemLocked; + break; + } + default: { + cmd->_lockType = MayaUsd::LayerLockType::LayerLock_Unlocked; + break; + } + } + cmd->_includeSublayers = includeSublayers; cmd->_proxyShapePath = proxyShapeName.asChar(); _subCommands.push_back(std::move(cmd)); } diff --git a/lib/mayaUsd/commands/layerEditorWindowCommand.cpp b/lib/mayaUsd/commands/layerEditorWindowCommand.cpp index ba4ee236ce..9c71fd48d5 100644 --- a/lib/mayaUsd/commands/layerEditorWindowCommand.cpp +++ b/lib/mayaUsd/commands/layerEditorWindowCommand.cpp @@ -47,6 +47,7 @@ DEF_FLAG(al, layerAppearsLocked) DEF_FLAG(lo, layerIsLocked) DEF_FLAG(as, layerAppearsSystemLocked) DEF_FLAG(ls, layerIsSystemLocked) +DEF_FLAG(ll, layerHasSubLayers) // edit flags DEF_FLAG(rs, removeSubLayer) @@ -60,13 +61,14 @@ DEF_FLAG(pl, printLayer) DEF_FLAG(cl, clearLayer) DEF_FLAG(sp, selectPrimsWithSpec) DEF_FLAG(lk, lockLayer) +DEF_FLAG(la, lockLayerAndSubLayers) const MString WORKSPACE_CONTROL_NAME = "mayaUsdLayerEditor"; } // namespace namespace MAYAUSD_NS_DEF { -// AbstractLayerEditorCreator implememtation +// AbstractLayerEditorCreator implementation AbstractLayerEditorCreator* AbstractLayerEditorCreator::_instance = nullptr; @@ -134,6 +136,7 @@ MSyntax LayerEditorWindowCommand::createSyntax() ADD_FLAG(layerIsLocked); ADD_FLAG(layerAppearsSystemLocked); ADD_FLAG(layerIsSystemLocked); + ADD_FLAG(layerHasSubLayers); ADD_FLAG(removeSubLayer); ADD_FLAG(saveEdits); @@ -146,6 +149,7 @@ MSyntax LayerEditorWindowCommand::createSyntax() ADD_FLAG(clearLayer); ADD_FLAG(selectPrimsWithSpec); ADD_FLAG(lockLayer); + ADD_FLAG(lockLayerAndSubLayers); // editor name syntax.addArg(MSyntax::kString); @@ -331,6 +335,7 @@ MStatus LayerEditorWindowCommand::handleQueries( HANDLE_Q_FLAG(layerIsLocked) HANDLE_Q_FLAG(layerAppearsSystemLocked) HANDLE_Q_FLAG(layerIsSystemLocked) + HANDLE_Q_FLAG(layerHasSubLayers) if (argParser.isFlagSet(FLAG(proxyShape)) && argParser.isQuery()) { setResult(layerEditor->proxyShapeName().c_str()); @@ -370,6 +375,7 @@ MStatus LayerEditorWindowCommand::handleEdits( HANDLE_E_FLAG(clearLayer) HANDLE_E_FLAG(selectPrimsWithSpec) HANDLE_E_FLAG(lockLayer) + HANDLE_E_FLAG(lockLayerAndSubLayers) return MS::kSuccess; } diff --git a/lib/usd/ui/layerEditor/abstractCommandHook.h b/lib/usd/ui/layerEditor/abstractCommandHook.h index e2b29cce67..828729bf9f 100644 --- a/lib/usd/ui/layerEditor/abstractCommandHook.h +++ b/lib/usd/ui/layerEditor/abstractCommandHook.h @@ -35,7 +35,7 @@ typedef PXR_NS::UsdStageRefPtr UsdStage; class SessionState; /** - * @brief The Abstact Command Hook contains all the methods which are used to modify USD layers and + * @brief The Abstract Command Hook contains all the methods which are used to modify USD layers and * stages. These methods will be "hooked" by the MayaCommandHook derived class to call maya mel * commands to do the work. * @@ -82,7 +82,9 @@ class AbstractCommandHook virtual void muteSubLayer(UsdLayer usdLayer, bool muteIt) = 0; // Sets the lock state on a layer - virtual void lockSubLayer(UsdLayer usdLayer, MayaUsd::LayerLockType lockState) = 0; + virtual void + lockLayer(UsdLayer usdLayer, MayaUsd::LayerLockType lockState, bool includeSubLayers) + = 0; // Checks if the file layer or its sublayers are accessible on disk, and updates the system-lock // status. @@ -126,10 +128,6 @@ class AbstractCommandHook protected: virtual void executeDelayedCommands() = 0; - // Checks if the file layer is accessible on disk, and updates the system-lock status - // accordingly. - virtual void _refreshLayerSystemLock(UsdLayer usdLayer) = 0; - SessionState* _sessionState; int _delayCount { 0 }; }; @@ -137,7 +135,7 @@ class AbstractCommandHook /** * @brief When executing multiple commands, it may sometimes be necessary to delay. * the execution until all commands are issued. For example, when processing - * multiple elements in the slection, but the command itself might change the + * multiple elements in the selection, but the command itself might change the * selection. */ class DelayAbstractCommandHook diff --git a/lib/usd/ui/layerEditor/layerTreeItem.cpp b/lib/usd/ui/layerEditor/layerTreeItem.cpp index 2f958d05d2..a4c0a48768 100644 --- a/lib/usd/ui/layerEditor/layerTreeItem.cpp +++ b/lib/usd/ui/layerEditor/layerTreeItem.cpp @@ -304,6 +304,13 @@ bool LayerTreeItem::appearsSystemLocked() const return false; } +bool LayerTreeItem::hasSubLayers() const +{ + if (!_layer) + return false; + return _layer->GetNumSubLayerPaths() > 0; +} + bool LayerTreeItem::needsSaving() const { // If for any reason we don't hold a layer, then we cannot save it. diff --git a/lib/usd/ui/layerEditor/layerTreeItem.h b/lib/usd/ui/layerEditor/layerTreeItem.h index 86bf795532..6a8018a4d9 100644 --- a/lib/usd/ui/layerEditor/layerTreeItem.h +++ b/lib/usd/ui/layerEditor/layerTreeItem.h @@ -146,6 +146,8 @@ class LayerTreeItem : public QStandardItem // may not be system locked but by inference some of the action items of the layer // can appear as locked if the parent is system locked. bool appearsSystemLocked() const; + // Checks if this layer has any sub layers. + bool hasSubLayers() const; // used by draw delegate: returns how deep in the hierarchy we are int depth() const; diff --git a/lib/usd/ui/layerEditor/layerTreeModel.cpp b/lib/usd/ui/layerEditor/layerTreeModel.cpp index e7a8575670..aec75063d6 100644 --- a/lib/usd/ui/layerEditor/layerTreeModel.cpp +++ b/lib/usd/ui/layerEditor/layerTreeModel.cpp @@ -584,7 +584,10 @@ void LayerTreeModel::toggleMuteLayer(LayerTreeItem* item, bool* forcedState) _sessionState->commandHook()->muteSubLayer(item->layer(), !item->isMuted()); } -void LayerTreeModel::toggleLockLayer(LayerTreeItem* item, bool* forcedState /*= nullptr*/) +void LayerTreeModel::toggleLockLayer( + LayerTreeItem* item, + bool includeSublayers, + bool* forcedState /*= nullptr*/) { if (item->isInvalidLayer() || item->isSessionLayer() || item->isSystemLocked()) return; @@ -597,7 +600,7 @@ void LayerTreeModel::toggleLockLayer(LayerTreeItem* item, bool* forcedState /*= MayaUsd::LayerLockType toggledLockType = item->isLocked() ? MayaUsd::LayerLockType::LayerLock_Unlocked : MayaUsd::LayerLockType::LayerLock_Locked; - _sessionState->commandHook()->lockSubLayer(item->layer(), toggledLockType); + _sessionState->commandHook()->lockLayer(item->layer(), toggledLockType, includeSublayers); } } // namespace UsdLayerEditor diff --git a/lib/usd/ui/layerEditor/layerTreeModel.h b/lib/usd/ui/layerEditor/layerTreeModel.h index 10d3b7c0ab..6c6c6f3261 100644 --- a/lib/usd/ui/layerEditor/layerTreeModel.h +++ b/lib/usd/ui/layerEditor/layerTreeModel.h @@ -87,7 +87,7 @@ class LayerTreeModel void toggleMuteLayer(LayerTreeItem* item, bool* forcedState = nullptr); // lock layer management - void toggleLockLayer(LayerTreeItem* item, bool* forcedState = nullptr); + void toggleLockLayer(LayerTreeItem* item, bool includeSublayers, bool* forcedState = nullptr); // ask to select a layer in the near future void selectUsdLayerOnIdle(const PXR_NS::SdfLayerRefPtr& usdLayer); diff --git a/lib/usd/ui/layerEditor/layerTreeView.cpp b/lib/usd/ui/layerEditor/layerTreeView.cpp index 2f306432b9..855bd8565f 100644 --- a/lib/usd/ui/layerEditor/layerTreeView.cpp +++ b/lib/usd/ui/layerEditor/layerTreeView.cpp @@ -342,6 +342,12 @@ void LayerTreeView::onMuteLayer(const QString& undoName) const } void LayerTreeView::onLockLayer(const QString& undoName) const +{ + bool includeSubLayers = false; + onLockLayerAndSublayers(undoName, includeSubLayers); +} + +void LayerTreeView::onLockLayerAndSublayers(const QString& undoName, bool includeSublayers) const { DelayAbstractCommandHook delayed(*_model->sessionState()->commandHook()); @@ -356,7 +362,7 @@ void LayerTreeView::onLockLayer(const QString& undoName) const UndoContext context(params.commandHook, params.name); for (auto item : *params.selection) { - item->parentModel()->toggleLockLayer(item, &isLocked); + item->parentModel()->toggleLockLayer(item, includeSublayers, &isLocked); } } @@ -551,7 +557,8 @@ void LayerTreeView::onLockLayerButtonPushed() { auto item = currentLayerItem(); if (item && !item->isSystemLocked()) { - item->parentModel()->toggleLockLayer(item); + bool includeSublayers = false; + item->parentModel()->toggleLockLayer(item, includeSublayers); } // need to force redraw of everything otherwise redraw isn't right update(); diff --git a/lib/usd/ui/layerEditor/layerTreeView.h b/lib/usd/ui/layerEditor/layerTreeView.h index a30bc28119..70fa0fa298 100644 --- a/lib/usd/ui/layerEditor/layerTreeView.h +++ b/lib/usd/ui/layerEditor/layerTreeView.h @@ -97,6 +97,7 @@ class LayerTreeView : public QTreeView void onAddParentLayer(const QString& undoName) const; void onMuteLayer(const QString& undoName) const; void onLockLayer(const QString& undoName) const; + void onLockLayerAndSublayers(const QString& undoName, bool includeSublayers) const; // QWidgets overrides virtual void paintEvent(QPaintEvent* event) override; diff --git a/lib/usd/ui/layerEditor/mayaCommandHook.cpp b/lib/usd/ui/layerEditor/mayaCommandHook.cpp index 849dce2d32..a4955accfb 100644 --- a/lib/usd/ui/layerEditor/mayaCommandHook.cpp +++ b/lib/usd/ui/layerEditor/mayaCommandHook.cpp @@ -203,12 +203,15 @@ void MayaCommandHook::muteSubLayer(UsdLayer usdLayer, bool muteIt) } // lock, system-lock or unlock the given layer -void MayaCommandHook::lockSubLayer(UsdLayer usdLayer, MayaUsd::LayerLockType lockState) +void MayaCommandHook::lockLayer( + UsdLayer usdLayer, + MayaUsd::LayerLockType lockState, + bool includeSubLayers) { std::string cmd; cmd = "mayaUsdLayerEditor -edit -lockLayer "; cmd += std::to_string(lockState); - + cmd += includeSubLayers ? " 1" : " 0"; cmd += quote(proxyShapePath()); cmd += quote(usdLayer->GetIdentifier()); executeMel(cmd); @@ -216,46 +219,13 @@ void MayaCommandHook::lockSubLayer(UsdLayer usdLayer, MayaUsd::LayerLockType loc void MayaCommandHook::refreshLayerSystemLock(UsdLayer usdLayer, bool refreshSubLayers /*= false*/) { - if (refreshSubLayers) { - bool includeTopLayer = true; - auto allLayers = MayaUsd::getAllSublayerRefs(usdLayer, includeTopLayer); - for (auto layer : allLayers) { - _refreshLayerSystemLock(layer); - } - } else { - _refreshLayerSystemLock(usdLayer); - } -} - -void MayaCommandHook::_refreshLayerSystemLock(UsdLayer usdLayer) -{ - // Anonymous layers do not need to be checked. - if (usdLayer && !usdLayer->IsAnonymous()) { - // Check if the layer's write permissions have changed. - std::string assetPath = usdLayer->GetResolvedPath(); - std::replace(assetPath.begin(), assetPath.end(), '\\', '/'); - - if (!assetPath.empty()) { - MString commandString; - // -w checks if file exists and is writable. - commandString.format("filetest -w \"^1s\"", MString(assetPath.c_str())); - MIntArray result; - // filetest is NOT undoable - MGlobal::executeCommand(commandString, result, /*display*/ false, /*undo*/ false); - if (result.length() > 0) { - - if (result[0] == 1 && MayaUsd::isLayerSystemLocked(usdLayer)) { - // If the file has write permissions and the layer is currently system-locked: - // Unlock the layer - lockSubLayer(usdLayer, MayaUsd::LayerLockType::LayerLock_Unlocked); - } else if (result[0] == 0 && !MayaUsd::isLayerSystemLocked(usdLayer)) { - // If the file doesn't have write permissions and the layer is currently not - // system-locked: System-lock the layer - lockSubLayer(usdLayer, MayaUsd::LayerLockType::LayerLock_SystemLocked); - } - } - } - } + std::string cmd; + cmd = "mayaUsdLayerEditor -edit -refreshSystemLock "; + cmd += quote(proxyShapePath()); + cmd += " "; + cmd += std::to_string(refreshSubLayers); + cmd += quote(usdLayer->GetIdentifier()); + executeMel(cmd); } // Help menu callback diff --git a/lib/usd/ui/layerEditor/mayaCommandHook.h b/lib/usd/ui/layerEditor/mayaCommandHook.h index 576e8328be..c1565d846e 100644 --- a/lib/usd/ui/layerEditor/mayaCommandHook.h +++ b/lib/usd/ui/layerEditor/mayaCommandHook.h @@ -64,7 +64,8 @@ class MayaCommandHook : public AbstractCommandHook void muteSubLayer(UsdLayer usdLayer, bool muteIt) override; // lock, system-lock or unlock the given layer - void lockSubLayer(UsdLayer usdLayer, MayaUsd::LayerLockType lockState) override; + void + lockLayer(UsdLayer usdLayer, MayaUsd::LayerLockType lockState, bool includeSubLayers) override; // Checks if the file layer or its sublayers are accessible on disk, and updates the system-lock // status. @@ -94,10 +95,6 @@ class MayaCommandHook : public AbstractCommandHook protected: std::string proxyShapePath(); - // Checks if the file layer or its sublayers are accessible on disk, and updates the system-lock - // status. - void _refreshLayerSystemLock(UsdLayer usdLayer) override; - std::string executeMel(const std::string& commandString); void executePython(const std::string& commandString); diff --git a/lib/usd/ui/layerEditor/mayaLayerEditorWindow.cpp b/lib/usd/ui/layerEditor/mayaLayerEditorWindow.cpp index 580a4fa545..c7ba90af1b 100644 --- a/lib/usd/ui/layerEditor/mayaLayerEditorWindow.cpp +++ b/lib/usd/ui/layerEditor/mayaLayerEditorWindow.cpp @@ -163,6 +163,7 @@ bool MayaLayerEditorWindow::layerAppearsLocked() { CALL_CURRENT_ITEM(appearsLock bool MayaLayerEditorWindow::layerIsLocked() { CALL_CURRENT_ITEM(isLocked); } bool MayaLayerEditorWindow::layerAppearsSystemLocked() { CALL_CURRENT_ITEM(appearsSystemLocked); } bool MayaLayerEditorWindow::layerIsSystemLocked() { CALL_CURRENT_ITEM(isSystemLocked); } +bool MayaLayerEditorWindow::layerHasSubLayers() { CALL_CURRENT_ITEM(hasSubLayers); } std::string MayaLayerEditorWindow::proxyShapeName() const { @@ -207,6 +208,16 @@ void MayaLayerEditorWindow::lockLayer() } } +void MayaLayerEditorWindow::lockLayerAndSubLayers() +{ + auto item = treeView()->currentLayerItem(); + if (item != nullptr) { + QString name = item->isLocked() ? "Unlock Layer and Sublayers" : "Lock Layer and Sublayers"; + bool includeSubLayers = true; + treeView()->onLockLayerAndSublayers(name, includeSubLayers); + } +} + void MayaLayerEditorWindow::addParentLayer() { QString name = "Add Parent Layer"; diff --git a/lib/usd/ui/layerEditor/mayaLayerEditorWindow.h b/lib/usd/ui/layerEditor/mayaLayerEditorWindow.h index 0839c25b6b..43b84e9f94 100644 --- a/lib/usd/ui/layerEditor/mayaLayerEditorWindow.h +++ b/lib/usd/ui/layerEditor/mayaLayerEditorWindow.h @@ -63,6 +63,7 @@ class MayaLayerEditorWindow bool layerIsLocked() override; bool layerAppearsSystemLocked() override; bool layerIsSystemLocked() override; + bool layerHasSubLayers() override; void removeSubLayer() override; void saveEdits() override; @@ -76,6 +77,7 @@ class MayaLayerEditorWindow void selectPrimsWithSpec() override; void updateLayerModel() override; void lockLayer() override; + void lockLayerAndSubLayers() override; void selectProxyShape(const char* shapePath) override; diff --git a/plugin/adsk/scripts/mayaUSDRegisterStrings.mel b/plugin/adsk/scripts/mayaUSDRegisterStrings.mel index 78b8dca2d9..d30f957efe 100644 --- a/plugin/adsk/scripts/mayaUSDRegisterStrings.mel +++ b/plugin/adsk/scripts/mayaUSDRegisterStrings.mel @@ -59,6 +59,7 @@ global proc mayaUSDRegisterStrings() register("kMenuLayerEditorAnn", "Organize and edit USD data in layers"); register("kMenuLoadSublayers", "Load Sublayers..."); register("kMenuLock", "Lock"); + register("kMenuLockLayerAndSublayers", "Lock Layer and Sublayers"); register("kMenuMute", "Mute"); register("kMenuPrintToScriptEditor", "Print to Script Editor"); register("kMenuRemove", "Remove"); @@ -75,6 +76,7 @@ global proc mayaUSDRegisterStrings() register("kMenuSetAs", "Set As..."); register("kMenuSaveEdits", "Save Edits"); register("kMenuUnlock", "Unlock"); + register("kMenuUnlockLayerAndSublayers", "Unlock Layer and Sublayers"); register("kMenuUnmute", "Unmute"); register("kPointInstances", "Point Instances"); register("kPurposeAnn", "Toggle purpose categories on and off to change their visibility in the viewport."); diff --git a/plugin/adsk/scripts/mayaUsdMenu.mel b/plugin/adsk/scripts/mayaUsdMenu.mel index df99ca7f00..ccdb3f13cd 100644 --- a/plugin/adsk/scripts/mayaUsdMenu.mel +++ b/plugin/adsk/scripts/mayaUsdMenu.mel @@ -873,6 +873,7 @@ global proc mayaUsdMenu_layerEditorContextMenu(string $panelName) { int $appearsSystemLocked = `mayaUsdLayerEditorWindow -q -layerAppearsSystemLocked $panelName`; int $isSystemLocked = `mayaUsdLayerEditorWindow -q -layerIsSystemLocked $panelName`; int $isIncoming = `mayaUsdLayerEditorWindow -q -isIncomingLayer $panelName`; + int $hasSublayers = `mayaUsdLayerEditorWindow -q -layerHasSubLayers $panelName`; string $proxyShape = `mayaUsdLayerEditorWindow -q -proxyShape $panelName`; string $label; @@ -939,6 +940,16 @@ global proc mayaUsdMenu_layerEditorContextMenu(string $panelName) { menuItem -label $label -enable $enabled -c $cmd; } + if (!$isSessionLayer && $hasSublayers) { + if ($isLocked) + $label = getMayaUsdString("kMenuUnlockLayerAndSublayers"); + else + $label = getMayaUsdString("kMenuLockLayerAndSublayers"); + $cmd = makeCommand($panelName, "lockLayerAndSubLayers"); + $enabled = !$isSystemLocked; + menuItem -label $label -enable $enabled -c $cmd; + } + $label = getMayaUsdString("kMenuPrintToScriptEditor"); $cmd = makeCommand($panelName, "printLayer"); $enabled = 1; diff --git a/test/lib/testMayaUsdLayerEditorCommands.py b/test/lib/testMayaUsdLayerEditorCommands.py index 710e9a6d20..86e9d9827c 100644 --- a/test/lib/testMayaUsdLayerEditorCommands.py +++ b/test/lib/testMayaUsdLayerEditorCommands.py @@ -546,23 +546,23 @@ def createLayer(index): self.assertTrue(subLayer.permissionToEdit) # Locking a layer - cmds.mayaUsdLayerEditor(subLayer.identifier, edit=True, lockLayer=(1, shapePath)) + cmds.mayaUsdLayerEditor(subLayer.identifier, edit=True, lockLayer=(1, 0, shapePath)) self.assertFalse(subLayer.permissionToEdit) cmds.undo() self.assertTrue(subLayer.permissionToEdit) cmds.redo() self.assertFalse(subLayer.permissionToEdit) # Unlocking a layer - cmds.mayaUsdLayerEditor(subLayer.identifier, edit=True, lockLayer=(0, shapePath)) + cmds.mayaUsdLayerEditor(subLayer.identifier, edit=True, lockLayer=(0, 0, shapePath)) self.assertTrue(subLayer.permissionToEdit) # System locking a layer - cmds.mayaUsdLayerEditor(subLayer.identifier, edit=True, lockLayer=(2, shapePath)) + cmds.mayaUsdLayerEditor(subLayer.identifier, edit=True, lockLayer=(2, 0, shapePath)) self.assertFalse(subLayer.permissionToEdit) self.assertFalse(subLayer.permissionToSave) cmds.undo() self.assertTrue(subLayer.permissionToEdit) - - def testLayerLockWritePermission(self): + + def testLockLayerAndSubLayers(self): # FileBacked Layer Write Permission # 1- Loading the test scene rootLayerPath = testUtils.getTestScene("layerLocking", "layerLocking.usda") @@ -571,7 +571,7 @@ def testLayerLockWritePermission(self): layerLockingShapes = cmds.ls(type="mayaUsdProxyShapeBase", long=True) proxyShapePath = layerLockingShapes[0] # 2- Setting a system lock on a layer loaded from a file - cmds.mayaUsdLayerEditor(topLayer.identifier, edit=True, lockLayer=(2, proxyShapePath)) + cmds.mayaUsdLayerEditor(topLayer.identifier, edit=True, lockLayer=(2, 0, proxyShapePath)) self.assertFalse(topLayer.permissionToEdit) self.assertFalse(topLayer.permissionToSave) # 3- Refreshing the system lock should remove the lock if the file is writable @@ -579,6 +579,25 @@ def testLayerLockWritePermission(self): self.assertTrue(topLayer.permissionToEdit) self.assertTrue(topLayer.permissionToSave) + def testLayerLockWritePermission(self): + # Locking a layer and its sublayer + # 1- Loading the test scene + rootLayerPath = testUtils.getTestScene("layerLocking", "layerLocking.usda") + stage = Usd.Stage.Open(rootLayerPath) + topLayer = stage.GetRootLayer(); + layerLockingShapes = cmds.ls(type="mayaUsdProxyShapeBase", long=True) + proxyShapePath = layerLockingShapes[0] + # 2- Setting a lock on the top layer with the option to lock its sublayer + cmds.mayaUsdLayerEditor(topLayer.identifier, edit=True, lockLayer=(1, 1, proxyShapePath)) + self.assertFalse(topLayer.permissionToEdit) + # 3- Check that sublayer is also locked + subLayer = Sdf.Layer.FindRelativeToLayer(topLayer, topLayer.subLayerPaths[0]) + self.assertFalse(subLayer.permissionToEdit) + # 4- Undo and check that both top and sublayer are unlocked + cmds.undo() + self.assertTrue(topLayer.permissionToEdit) + self.assertTrue(subLayer.permissionToEdit) + def testMuteLayer(self): """ test 'mayaUsdLayerEditor' command 'muteLayer' paramater """ diff --git a/test/testSamples/layerLocking/layerLocking.usda b/test/testSamples/layerLocking/layerLocking.usda index 64aa4a3222..375a82656d 100644 --- a/test/testSamples/layerLocking/layerLocking.usda +++ b/test/testSamples/layerLocking/layerLocking.usda @@ -1,4 +1,9 @@ #usda 1.0 +( + subLayers = [ + @layerLockingSubLayer.usda@ + ] +) def Cube "Cube1" { diff --git a/test/testSamples/layerLocking/layerLockingSubLayer.usda b/test/testSamples/layerLocking/layerLockingSubLayer.usda new file mode 100644 index 0000000000..afcee980c3 --- /dev/null +++ b/test/testSamples/layerLocking/layerLockingSubLayer.usda @@ -0,0 +1,2 @@ +#usda 1.0 +