diff --git a/lib/mayaUsd/utils/utilFileSystem.cpp b/lib/mayaUsd/utils/utilFileSystem.cpp index ad10d2ca73..bce8debdfa 100644 --- a/lib/mayaUsd/utils/utilFileSystem.cpp +++ b/lib/mayaUsd/utils/utilFileSystem.cpp @@ -48,6 +48,15 @@ std::string generateUniqueName() } return uniqueName; } + +using PostponedRelativePaths = std::map>; + +static PostponedRelativePaths& getPostponedRelativePaths() +{ + static PostponedRelativePaths sPaths; + return sPaths; +} + } // namespace PXR_NAMESPACE_USING_DIRECTIVE @@ -283,6 +292,63 @@ std::string UsdMayaUtilFileSystem::getPathRelativeToLayerFile( return relativePathAndSuccess.first; } +void UsdMayaUtilFileSystem::markPathAsPostponedRelative( + const PXR_NS::SdfLayerHandle& layer, + const std::string& contentPath) +{ + ghc::filesystem::path filePath(contentPath); + auto& postponedRelativePaths = getPostponedRelativePaths(); + postponedRelativePaths[layer].insert(filePath.lexically_normal()); +} + +void UsdMayaUtilFileSystem::unmarkPathAsPostponedRelative( + const PXR_NS::SdfLayerHandle& layer, + const std::string& contentPath) +{ + auto& postponedRelativePaths = getPostponedRelativePaths(); + auto layerEntry = postponedRelativePaths.find(layer); + if (layerEntry != postponedRelativePaths.end()) { + ghc::filesystem::path filePath(contentPath); + layerEntry->second.erase(filePath.lexically_normal()); + } +} + +void UsdMayaUtilFileSystem::updatePostponedRelativePaths( + const PXR_NS::SdfLayerHandle& layer, + const std::string& layerFileName) +{ + // Find the layer entry + auto& postponedRelativePaths = getPostponedRelativePaths(); + auto layerEntry = postponedRelativePaths.find(layer); + if (layerEntry == postponedRelativePaths.end()) { + return; + } + + // Update sublayer paths + auto subLayerPaths = layer->GetSubLayerPaths(); + for (size_t j = 0; j < subLayerPaths.size(); ++j) { + const auto subLayer = SdfLayer::FindRelativeToLayer(layer, subLayerPaths[j]); + if (!subLayer) { + continue; + } + + ghc::filesystem::path filePath(subLayer->GetRealPath()); + filePath = filePath.lexically_normal(); + + auto it = layerEntry->second.find(filePath); + if (it == layerEntry->second.end()) { + continue; + } + + auto anchorDir = ghc::filesystem::path(layerFileName).lexically_normal().remove_filename(); + subLayerPaths[j] + = getPathRelativeToDirectory(filePath.generic_string(), anchorDir.generic_string()); + } + + // Erase the layer entry + postponedRelativePaths.erase(layerEntry); +} + bool UsdMayaUtilFileSystem::prepareLayerSaveUILayer( const PXR_NS::SdfLayerHandle& layer, bool useSceneFileForRoot) diff --git a/lib/mayaUsd/utils/utilFileSystem.h b/lib/mayaUsd/utils/utilFileSystem.h index 72c3982cae..86b403da1d 100644 --- a/lib/mayaUsd/utils/utilFileSystem.h +++ b/lib/mayaUsd/utils/utilFileSystem.h @@ -128,6 +128,28 @@ MAYAUSD_CORE_PUBLIC std::string getPathRelativeToLayerFile(const std::string& fileName, const PXR_NS::SdfLayerHandle& layer); +/*! \brief Marks a certain file path inside the layer to be made relative in a postponed fashion. +The marked file paths will be turned into relative paths upon calling updatePostponedRelativePaths. + */ +MAYAUSD_CORE_PUBLIC +void markPathAsPostponedRelative( + const PXR_NS::SdfLayerHandle& layer, + const std::string& contentPath); + +/*! \brief Unmarks file path which was marked through the call to markPathAsPostponedRelative. + */ +MAYAUSD_CORE_PUBLIC +void unmarkPathAsPostponedRelative( + const PXR_NS::SdfLayerHandle& layer, + const std::string& contentPath); + +/*! \brief Turns the file paths marked through the call 'markPathAsPostponedRelative' to relative. + */ +MAYAUSD_CORE_PUBLIC +void updatePostponedRelativePaths( + const PXR_NS::SdfLayerHandle& layer, + const std::string& layerFileName); + /*! \brief returns the flag specifying whether USD file paths should be saved as relative to Maya * scene file */ diff --git a/lib/mayaUsd/utils/utilSerialization.cpp b/lib/mayaUsd/utils/utilSerialization.cpp index c3dabf969f..974913c1d0 100644 --- a/lib/mayaUsd/utils/utilSerialization.cpp +++ b/lib/mayaUsd/utils/utilSerialization.cpp @@ -294,6 +294,8 @@ bool saveLayerWithFormat( const std::string& formatArg = requestedFormatArg.empty() ? usdFormatArgOption() : requestedFormatArg; + UsdMayaUtilFileSystem::updatePostponedRelativePaths(layer, filePath); + if (isCompatibleWithSave(layer, filePath, formatArg)) { if (!layer->Save()) { return false; diff --git a/lib/usd/ui/layerEditor/layerTreeItem.cpp b/lib/usd/ui/layerEditor/layerTreeItem.cpp index 980d54e7bf..a6039e22d6 100644 --- a/lib/usd/ui/layerEditor/layerTreeItem.cpp +++ b/lib/usd/ui/layerEditor/layerTreeItem.cpp @@ -395,13 +395,19 @@ void LayerTreeItem::saveAnonymousLayer() sessionState->rootLayerPathChanged(fileName); } else { auto parentItem = parentLayerItem(); - - std::string relativePathAnchor; - if (parentItem && UsdMayaUtilFileSystem::requireUsdPathsRelativeToParentLayer()) { - fileName = UsdMayaUtilFileSystem::getPathRelativeToLayerFile( - fileName, parentItem->layer()); - relativePathAnchor - = UsdMayaUtilFileSystem::getLayerFileDir(parentItem->layer()); + auto parentLayer = parentItem ? parentItem->layer() : nullptr; + if (parentLayer) { + if (UsdMayaUtilFileSystem::requireUsdPathsRelativeToParentLayer()) { + if (!parentLayer->IsAnonymous()) { + fileName = UsdMayaUtilFileSystem::getPathRelativeToLayerFile( + fileName, parentLayer); + } else { + UsdMayaUtilFileSystem::markPathAsPostponedRelative( + parentLayer, fileName); + } + } else { + UsdMayaUtilFileSystem::unmarkPathAsPostponedRelative(parentLayer, fileName); + } } // Note: we need to open the layer with the absolute path. The relative path is only @@ -478,8 +484,16 @@ void LayerTreeItem::loadSubLayers(QWidget* in_parent) if (dlg.pathsToLoad().size() > 0) { const int index = 0; UndoContext context(commandHook(), "Load Layers"); - for (auto path : dlg.pathsToLoad()) { + for (const auto& path : dlg.pathsToLoad()) { context.hook()->insertSubLayerPath(layer(), path, index); + + if (UsdMayaUtilFileSystem::requireUsdPathsRelativeToParentLayer()) { + if (layer()->IsAnonymous()) { + UsdMayaUtilFileSystem::markPathAsPostponedRelative(layer(), path); + } + } else { + UsdMayaUtilFileSystem::unmarkPathAsPostponedRelative(layer(), path); + } } } } diff --git a/lib/usd/ui/layerEditor/loadLayersDialog.cpp b/lib/usd/ui/layerEditor/loadLayersDialog.cpp index 637b198592..5b3709dd34 100644 --- a/lib/usd/ui/layerEditor/loadLayersDialog.cpp +++ b/lib/usd/ui/layerEditor/loadLayersDialog.cpp @@ -303,7 +303,7 @@ void LoadLayersDialog::onOpenBrowser() return; // Replace selected filenames with relative ones if enabled. - if (requireUsdPathsRelativeToParentLayer()) { + if (requireUsdPathsRelativeToParentLayer() && parentLayer && !parentLayer->IsAnonymous()) { for (std::string& fileName : files) { fileName = getPathRelativeToLayerFile(fileName, parentLayer); } diff --git a/plugin/adsk/scripts/mayaUSDRegisterStrings.py b/plugin/adsk/scripts/mayaUSDRegisterStrings.py index b9e17ca794..11c30d7468 100644 --- a/plugin/adsk/scripts/mayaUSDRegisterStrings.py +++ b/plugin/adsk/scripts/mayaUSDRegisterStrings.py @@ -43,7 +43,7 @@ def mayaUSDRegisterStrings(): register("kMakePathRelativeToImageEditTargetLayer", "Make Path Relative to Edit Target Layer Directory") register("kMakePathRelativeToImageEditTargetLayerAnn", "Enable to activate relative pathing to your current edit target layer's directory.\nIf this option is disabled, verify that your target layer is not anonymous and save it to disk.") register("kMakePathRelativeToParentLayer", "Make Path Relative to Parent Layer Directory") - register("kMakePathRelativeToParentLayerAnn", "Enable to activate relative pathing to your current parent layer's directory.\nIf this option is disabled, verify that your parent layer is not anonymous and save it to disk.") + register("kMakePathRelativeToParentLayerAnn", "Enable to activate relative pathing to your current parent layer's directory.") register("kUnresolvedPath", "Path Preview:") register("kUnresolvedPathAnn", "This field indicates the path with the file name currently chosen in your text input. Note: This is the string that will be written out to the file in the chosen directory in order to enable portability.") register("kCompositionArcOptions", "Composition Arc Options") diff --git a/plugin/adsk/scripts/mayaUsd_USDRootFileRelative.py b/plugin/adsk/scripts/mayaUsd_USDRootFileRelative.py index 719d72c906..20eaabbdee 100644 --- a/plugin/adsk/scripts/mayaUsd_USDRootFileRelative.py +++ b/plugin/adsk/scripts/mayaUsd_USDRootFileRelative.py @@ -139,6 +139,8 @@ def uiInit(cls, parentLayout): showPreviewFields = True if cls.kRelativeToWhat == 'SceneFile': showPreviewFields = cmds.file(q=True, exists=True) + elif cls.kRelativeToWhat == 'ParentLayer': + showPreviewFields = bool(cls._relativeToDir) cmds.textFieldGrp(cls.kUnresolvedPathTextField, edit=True, visible=showPreviewFields) @@ -330,8 +332,9 @@ def uiInit(cls, parentLayout, filterType, parentLayerPath): ''' cls.setRelativeFilePathRoot(parentLayerPath) cls._relativeToDir = parentLayerPath - # If the parent layer is not saved, then the checkbox and label should be disabled. - cls._canBeRelative = bool(cls._relativeToDir) + # Even if the parent layer is not saved, the file can still be marked as relative. + # In that case we use a technique to set the path to relative in a postponed fashion. + cls._canBeRelative = True super(usdSubLayerFileRelative, cls).uiInit(parentLayout) @classmethod diff --git a/plugin/adsk/scripts/mayaUsd_layerEditorFileDialogs.mel b/plugin/adsk/scripts/mayaUsd_layerEditorFileDialogs.mel index dedb01f994..9902d8c408 100644 --- a/plugin/adsk/scripts/mayaUsd_layerEditorFileDialogs.mel +++ b/plugin/adsk/scripts/mayaUsd_layerEditorFileDialogs.mel @@ -185,8 +185,9 @@ global proc UsdLayerEditor_LoadLayersFileDialogOptions_FileTypeChanged(string $p global proc string[] UsdLayerEditor_LoadLayersFileDialog(string $title, string $folder) { + // Always set parent path to empty to hide the file preview global string $gLayerParentPathUsdLayerEditorSaveFileDialog; - $gLayerParentPathUsdLayerEditorSaveFileDialog = $folder; + $gLayerParentPathUsdLayerEditorSaveFileDialog = ""; string $fileFilter = python("from mayaUsdUtils import getUSDDialogFileFilters; getUSDDialogFileFilters(False)"); $okCaption = getMayaUsdString("kLoad");