diff --git a/lib/mayaUsd/nodes/layerManager.cpp b/lib/mayaUsd/nodes/layerManager.cpp index fc63179ec5..3a51494021 100644 --- a/lib/mayaUsd/nodes/layerManager.cpp +++ b/lib/mayaUsd/nodes/layerManager.cpp @@ -163,10 +163,10 @@ void convertAnonymousLayersRecursive( parentPtr._proxyPath = basename; } else if (stage->GetSessionLayer() == layer) { parentPtr._layerParent = nullptr; - parentPtr._proxyPath.clear(); + parentPtr._proxyPath = basename; } else { parentPtr._layerParent = layer; - parentPtr._proxyPath.clear(); + parentPtr._proxyPath = basename; } std::vector sublayers = layer->GetSubLayerPaths(); @@ -788,7 +788,12 @@ BatchSaveResult LayerDatabase::saveUsdToUsdFiles() SdfLayerHandleVector allLayers = info.stage->GetLayerStack(false); for (auto layer : allLayers) { if (layer->PermissionToSave()) { - MayaUsd::utils::saveLayerWithFormat(layer); + if (!MayaUsd::utils::saveLayerWithFormat(layer)) { + MString errMsg; + MString layerName(layer->GetDisplayName().c_str()); + errMsg.format("Could not save layer ^1s.", layerName); + MGlobal::displayError(errMsg); + } } } } @@ -814,14 +819,22 @@ void LayerDatabase::convertAnonymousLayers( // to convertAnonymousLayersRecursive root = stage->GetRootLayer(); if (root->IsAnonymous()) { + const bool wasTargetLayer = (stage->GetEditTarget().GetLayer() == root); PXR_NS::SdfFileFormat::FileFormatArguments args; std::string newFileName = MayaUsd::utils::generateUniqueFileName(proxyName); if (UsdMayaUtilFileSystem::requireUsdPathsRelativeToMayaSceneFile()) { newFileName = UsdMayaUtilFileSystem::getPathRelativeToMayaSceneFile(newFileName); } - MayaUsd::utils::saveLayerWithFormat(root, newFileName); + if (!MayaUsd::utils::saveLayerWithFormat(root, newFileName)) { + MString errMsg; + MString layerName(root->GetDisplayName().c_str()); + errMsg.format("Could not save layer ^1s.", layerName); + MGlobal::displayError(errMsg); + } - MayaUsd::utils::setNewProxyPath(pShape->name(), UsdMayaUtil::convert(newFileName)); + SdfLayerRefPtr newLayer = SdfLayer::FindOrOpen(newFileName); + MayaUsd::utils::setNewProxyPath( + pShape->name(), UsdMayaUtil::convert(newFileName), newLayer, wasTargetLayer); } SdfLayerHandle session = stage->GetSessionLayer(); @@ -830,6 +843,7 @@ void LayerDatabase::convertAnonymousLayers( saveUsdLayerToMayaFile(session, true); + // TODO: should update the target layer of the proxy shape if the session was the target. setValueForAttr( proxyNode, MayaUsdProxyShapeBase::sessionLayerNameAttr, diff --git a/lib/mayaUsd/utils/util.cpp b/lib/mayaUsd/utils/util.cpp index 7efd90a3a3..ab2cf25e5e 100644 --- a/lib/mayaUsd/utils/util.cpp +++ b/lib/mayaUsd/utils/util.cpp @@ -240,18 +240,22 @@ MStatus UsdMayaUtil::GetMObjectByName(const std::string& nodeName, MObject& mObj return GetMObjectByName(MString(nodeName.c_str()), mObj); } -UsdStageRefPtr UsdMayaUtil::GetStageByProxyName(const std::string& proxyPath) +MayaUsdProxyShapeBase* UsdMayaUtil::GetProxyShapeByProxyName(const std::string& proxyPath) { MObject mobj; MStatus status = UsdMayaUtil::GetMObjectByName(proxyPath, mobj); - if (status == MStatus::kSuccess) { - MFnDependencyNode fn; - fn.setObject(mobj); - MayaUsdProxyShapeBase* pShape = static_cast(fn.userNode()); - return pShape ? pShape->getUsdStage() : nullptr; - } + if (status != MStatus::kSuccess) + return nullptr; - return nullptr; + MFnDependencyNode fn; + fn.setObject(mobj); + return static_cast(fn.userNode()); +} + +UsdStageRefPtr UsdMayaUtil::GetStageByProxyName(const std::string& proxyPath) +{ + MayaUsdProxyShapeBase* pShape = UsdMayaUtil::GetProxyShapeByProxyName(proxyPath); + return pShape ? pShape->getUsdStage() : nullptr; } MStatus UsdMayaUtil::GetPlugByName(const std::string& attrPath, MPlug& plug) diff --git a/lib/mayaUsd/utils/util.h b/lib/mayaUsd/utils/util.h index 16cac1a73a..45e9348ef1 100644 --- a/lib/mayaUsd/utils/util.h +++ b/lib/mayaUsd/utils/util.h @@ -17,6 +17,7 @@ #define PXRUSDMAYA_UTIL_H #include +#include #include #include @@ -185,6 +186,10 @@ MStatus GetMObjectByName(const std::string& nodeName, MObject& mObj); MAYAUSD_CORE_PUBLIC MStatus GetMObjectByName(const MString& nodeName, MObject& mObj); +/// Gets the proxy shape node named \p nodeName. +MAYAUSD_CORE_PUBLIC +MayaUsdProxyShapeBase* GetProxyShapeByProxyName(const std::string& nodeName); + /// Gets the UsdStage for the proxy shape node named \p nodeName. MAYAUSD_CORE_PUBLIC UsdStageRefPtr GetStageByProxyName(const std::string& nodeName); diff --git a/lib/mayaUsd/utils/utilSerialization.cpp b/lib/mayaUsd/utils/utilSerialization.cpp index f0650d416e..272918de2e 100644 --- a/lib/mayaUsd/utils/utilSerialization.cpp +++ b/lib/mayaUsd/utils/utilSerialization.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -52,6 +53,7 @@ class RecursionDetector }; void populateChildren( + const std::string& proxyPath, const UsdStageRefPtr& stage, SdfLayerRefPtr layer, RecursionDetector* recursionDetector, @@ -71,13 +73,13 @@ void populateChildren( auto subLayer = PXR_NS::SdfLayer::FindOrOpen(actualPath); if (subLayer && !recursionDetector->contains(subLayer->GetRealPath())) { populateChildren( - stage, subLayer, recursionDetector, anonLayersToSave, dirtyLayersToSave); + proxyPath, stage, subLayer, recursionDetector, anonLayersToSave, dirtyLayersToSave); if (subLayer->IsAnonymous()) { MayaUsd::utils::LayerInfo info; info.stage = stage; info.layer = subLayer; - info.parent._proxyPath.clear(); + info.parent._proxyPath = proxyPath; info.parent._layerParent = layer; anonLayersToSave.push_back(info); } else if (subLayer->IsDirty()) { @@ -89,30 +91,41 @@ void populateChildren( recursionDetector->pop(); } -bool saveRootLayer(SdfLayerRefPtr layer, const std::string& proxy, bool savePathAsRelative) +void updateTargetLayer(const std::string& proxyNodeName, const SdfLayerRefPtr& layer) { - if (!layer || proxy.empty() || layer->IsAnonymous()) { - return false; + if (MayaUsdProxyShapeBase* proxyShape = UsdMayaUtil::GetProxyShapeByProxyName(proxyNodeName)) { + proxyShape->getUsdStage()->SetEditTarget(layer); } +} + +void updateRootLayer( + const std::string& proxy, + const std::string& layerPath, + const SdfLayerRefPtr& layer, + bool isTargetLayer) +{ + // Upda the root layer of the given proxy shape + if (layerPath.empty() || proxy.empty()) + return; - std::string fp = layer->GetRealPath(); #ifdef _WIN32 // Building a string that includes a file path for an executeCommand call // can be problematic, easier to just switch the path separator. - fp = TfStringReplace(fp, "\\", "/"); + const std::string fp = TfStringReplace(layerPath, "\\", "/"); +#else + const std::string& fp = layerPath; #endif - if (savePathAsRelative) { - fp = UsdMayaUtilFileSystem::getPathRelativeToMayaSceneFile(fp); - } - - MayaUsd::utils::setNewProxyPath(MString(proxy.c_str()), MString(fp.c_str())); - - return true; + MayaUsd::utils::setNewProxyPath( + MString(proxy.c_str()), MString(fp.c_str()), layer, isTargetLayer); } void updateAllCachedStageWithLayer(SdfLayerRefPtr originalLayer, const std::string& newFilePath) { + // Update all known stage caches managed by the Maya USD plugin that contained + // stages using the original anonymous layer so that new stagesusing new saved + // layer are created with the load rules and the muted layers of the original + // stage. SdfLayerRefPtr newLayer = SdfLayer::FindOrOpen(newFilePath); if (!newLayer) { TF_WARN("The filename %s is an invalid file name for a layer.", newFilePath.c_str()); @@ -205,14 +218,21 @@ USDUnsavedEditsOption serializeUsdEditsLocationOption() } } // namespace MAYAUSD_NS_DEF -void setNewProxyPath(const MString& proxyNodeName, const MString& newValue) +void setNewProxyPath( + const MString& proxyNodeName, + const MString& newRootLayerPath, + const SdfLayerRefPtr& layer, + bool isTargetLayer) { MString script; - script.format("setAttr -type \"string\" ^1s.filePath \"^2s\"", proxyNodeName, newValue); + script.format("setAttr -type \"string\" ^1s.filePath \"^2s\"", proxyNodeName, newRootLayerPath); MGlobal::executeCommand( script, /*display*/ true, /*undo*/ false); + + if (isTargetLayer) + updateTargetLayer(proxyNodeName.asChar(), layer); } static bool isCompatibleWithSave( @@ -300,7 +320,9 @@ SdfLayerRefPtr saveAnonymousLayer( const bool wasTargetLayer = (stage->GetEditTarget().GetLayer() == anonLayer); - saveLayerWithFormat(anonLayer, filePath, formatArg); + if (!saveLayerWithFormat(anonLayer, filePath, formatArg)) { + return nullptr; + } const bool isSubLayer = (parent._layerParent != nullptr); std::string relativePathAnchor; @@ -326,14 +348,12 @@ SdfLayerRefPtr saveAnonymousLayer( if (newLayer) { if (isSubLayer) { updateSubLayer(parent._layerParent, anonLayer, filePath); + updateTargetLayer(parent._proxyPath, newLayer); } else if (!parent._proxyPath.empty()) { - saveRootLayer(newLayer, parent._proxyPath, savePathAsRelative); + updateRootLayer(parent._proxyPath, filePath, newLayer, wasTargetLayer); } } - if (wasTargetLayer) - stage->SetEditTarget(newLayer); - return newLayer; } @@ -383,7 +403,7 @@ void getLayersToSaveFromProxy(const std::string& proxyPath, StageLayersToSave& l auto root = stage->GetRootLayer(); populateChildren( - stage, root, nullptr, layersInfo._anonLayers, layersInfo._dirtyFileBackedLayers); + proxyPath, stage, root, nullptr, layersInfo._anonLayers, layersInfo._dirtyFileBackedLayers); if (root->IsAnonymous()) { LayerInfo info; info.stage = stage; @@ -397,7 +417,12 @@ void getLayersToSaveFromProxy(const std::string& proxyPath, StageLayersToSave& l auto session = stage->GetSessionLayer(); populateChildren( - stage, session, nullptr, layersInfo._anonLayers, layersInfo._dirtyFileBackedLayers); + proxyPath, + stage, + session, + nullptr, + layersInfo._anonLayers, + layersInfo._dirtyFileBackedLayers); } } // namespace utils diff --git a/lib/mayaUsd/utils/utilSerialization.h b/lib/mayaUsd/utils/utilSerialization.h index 6501e16950..3e87bd44db 100644 --- a/lib/mayaUsd/utils/utilSerialization.h +++ b/lib/mayaUsd/utils/utilSerialization.h @@ -62,10 +62,15 @@ MAYAUSD_CORE_PUBLIC USDUnsavedEditsOption serializeUsdEditsLocationOption(); /*! \brief Utility function to update the file path attribute on the proxy shape - when an anonymous root layer gets exported to disk. + when an anonymous root layer gets exported to disk. Also optionally updates + the target layer if the anonymous layer was the target layer. */ MAYAUSD_CORE_PUBLIC -void setNewProxyPath(const MString& proxyNodeName, const MString& newValue); +void setNewProxyPath( + const MString& proxyNodeName, + const MString& newValue, + const SdfLayerRefPtr& layer, + bool isTargetLayer); struct LayerParent { diff --git a/lib/usd/ui/layerEditor/layerTreeItem.cpp b/lib/usd/ui/layerEditor/layerTreeItem.cpp index c67305a314..25f6d55c89 100644 --- a/lib/usd/ui/layerEditor/layerTreeItem.cpp +++ b/lib/usd/ui/layerEditor/layerTreeItem.cpp @@ -352,7 +352,12 @@ void LayerTreeItem::saveEditsNoPrompt() if (!isSessionLayer()) saveAnonymousLayer(); } else { - MayaUsd::utils::saveLayerWithFormat(layer()); + if (!MayaUsd::utils::saveLayerWithFormat(layer())) { + MString errMsg; + MString layerName(layer()->GetDisplayName().c_str()); + errMsg.format("Could not save layer ^1s.", layerName); + MGlobal::displayError(errMsg); + } } }