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

EMSUSD-622 - As a user, I'd like to add a relative sublayer on a anonymous layer #3353

Merged
merged 4 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
57 changes: 57 additions & 0 deletions lib/mayaUsd/utils/utilFileSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ std::string generateUniqueName()
}
return uniqueName;
}

static std::map<PXR_NS::SdfLayerHandle, std::set<ghc::filesystem::path>> sPostponedRelativePaths;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I know that it is not multi-thread safe anyway, but just for order-of-initilization of C++ globals, it is a better practice to put the static variable inside a static function that returns it because the C++ language standard guarantee hat the static will be initialized on first call (which avoid the order of init of globals problem) and ensure that this init is thread-safe.

So something like:

using RelativePaths = std::map<PXR_NS::SdfLayerHandle, std::set<ghc::filesystem::path>>;
static RelativePaths& getRelativePaths()
{
    static RelativePaths sPaths;
    return sPaths;
}


} // namespace

PXR_NAMESPACE_USING_DIRECTIVE
Expand Down Expand Up @@ -283,6 +286,60 @@ std::string UsdMayaUtilFileSystem::getPathRelativeToLayerFile(
return relativePathAndSuccess.first;
}

void UsdMayaUtilFileSystem::markPathAsPostponedRelative(
const PXR_NS::SdfLayerHandle& layer,
const std::string& contentPath)
{
ghc::filesystem::path filePath(contentPath);
sPostponedRelativePaths[layer].insert(filePath.lexically_normal());
}

void UsdMayaUtilFileSystem::unmarkPathAsPostponedRelative(
const PXR_NS::SdfLayerHandle& layer,
const std::string& contentPath)
{
auto layerEntry = sPostponedRelativePaths.find(layer);
if (layerEntry != sPostponedRelativePaths.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 layerEntry = sPostponedRelativePaths.find(layer);
if (layerEntry == sPostponedRelativePaths.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
sPostponedRelativePaths.erase(layerEntry);
}

bool UsdMayaUtilFileSystem::prepareLayerSaveUILayer(
const PXR_NS::SdfLayerHandle& layer,
bool useSceneFileForRoot)
Expand Down
22 changes: 22 additions & 0 deletions lib/mayaUsd/utils/utilFileSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down
2 changes: 2 additions & 0 deletions lib/mayaUsd/utils/utilSerialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
30 changes: 22 additions & 8 deletions lib/usd/ui/layerEditor/layerTreeItem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/usd/ui/layerEditor/loadLayersDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion plugin/adsk/scripts/mayaUSDRegisterStrings.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
7 changes: 5 additions & 2 deletions plugin/adsk/scripts/mayaUsd_USDRootFileRelative.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion plugin/adsk/scripts/mayaUsd_layerEditorFileDialogs.mel
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
Loading