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

Adds the ability to lock layers and sublayers at once #3646

Merged
merged 5 commits into from
Mar 8, 2024
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
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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do and undo stop at the first error and execute in the same order. For composite commands, the usual way to handle it is to record which were done so undo only undoes those that were actually successful. Also, undo usually execute in reverse order as do. Might be worthwhile to either execute as much as possible (execute all, return if any failed) or to undo on error.

For locking, these things are less critical, I don't think there will be anything bad so you can keep the simpler code that you currently have, but it is something to keep in mind.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great point!

In this implementation, the layer hierarchy is flattened and since locking only affects the local variables of each layer, the lock / unlock doesn't have to be in an order. I'll keep the error checking in mind going forward.

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