Skip to content

Commit

Permalink
Merge pull request #3646 from Autodesk/azharia/EMSUSD-879/Adds-Lock-S…
Browse files Browse the repository at this point in the history
…ublayer-Command

Adds the ability to lock layers and sublayers at once
  • Loading branch information
seando-adsk authored Mar 8, 2024
2 parents 521b50c + a16403e commit b735738
Show file tree
Hide file tree
Showing 20 changed files with 228 additions and 109 deletions.
6 changes: 4 additions & 2 deletions lib/mayaUsd/commands/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand All @@ -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 |
Expand All @@ -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 |
Expand Down
2 changes: 2 additions & 0 deletions lib/mayaUsd/commands/abstractLayerEditorWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
};
Expand Down
154 changes: 113 additions & 41 deletions lib/mayaUsd/commands/layerEditorCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<PXR_NS::SdfLayerRefPtr> 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;
Expand All @@ -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()
Expand Down Expand Up @@ -871,7 +898,9 @@ class LockLayer : public BaseCmd
globalSn->replaceWith(UsdUfe::recreateDescendants(_savedSn, path));
}

Ufe::Selection _savedSn;
Ufe::Selection _savedSn;
std::vector<MayaUsd::LayerLockType> _previousStates;
SdfLayerHandleVector _layers;
};

class RefreshSystemLockLayer : public BaseCmd
Expand Down Expand Up @@ -901,24 +930,42 @@ 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<std::shared_ptr<Impl::BaseCmd>> _lockCommands;
SdfLayerHandleVector _layers;

private:
std::string _quote(const std::string& string)
{
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.
Expand All @@ -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<Impl::LockLayer>();
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<Impl::LockLayer>();
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());
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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()) {
Expand All @@ -1220,8 +1279,21 @@ MStatus LayerEditorCommand::parseArgs(const MArgList& argList)
}

auto cmd = std::make_shared<Impl::LockLayer>();
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));
}
Expand Down
8 changes: 7 additions & 1 deletion lib/mayaUsd/commands/layerEditorWindowCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;

Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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;
}
Expand Down
12 changes: 5 additions & 7 deletions lib/usd/ui/layerEditor/abstractCommandHook.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -126,18 +128,14 @@ 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 };
};

/**
* @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
Expand Down
7 changes: 7 additions & 0 deletions lib/usd/ui/layerEditor/layerTreeItem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading

0 comments on commit b735738

Please sign in to comment.