PXR_NAMESPACE_OPEN_SCOPE bool UsdUtilsCopyLayerMetadata(const SdfLayerHandle &source, const SdfLayerHandle &destination, bool skipSublayers) { if (!TF_VERIFY(source && destination)) return false; SdfPrimSpecHandle sourcePseudo = source->GetPseudoRoot(); SdfPrimSpecHandle destPseudo = destination->GetPseudoRoot(); std::vector<TfToken> infoKeys = sourcePseudo->ListInfoKeys(); std::vector<TfToken>::iterator last = infoKeys.end(); if (skipSublayers){ last = std::remove_if(infoKeys.begin(), last, [](TfToken key) { return (key == SdfFieldKeys->SubLayers || key == SdfFieldKeys->SubLayerOffsets); }); } for (auto key = infoKeys.begin(); key != last; ++key){ destPseudo->SetInfo(*key, sourcePseudo->GetInfo(*key)); } return true; }
// public facing API // ---------------------------------------------------------------------------- bool UsdUtilsStitchClipsTopology(const SdfLayerHandle& topologyLayer, const _ClipFileVector& clipLayerFiles) { // XXX: This is necessary for any C++ API which may be called though // python. Since this will spawn workers(in WorkParallelForN) which // will need to acquire the GIL, we need to explicitly release it. TF_PY_ALLOW_THREADS_IN_SCOPE(); // Prepare topology layer for editing if (!_LayerIsWritable(topologyLayer)) { return false; } else { topologyLayer->Clear(); } // Open all clip layers and validate clipPath SdfLayerRefPtrVector clipLayers; const bool clipLayersAreValid = _OpenClipLayers(&clipLayers, clipLayerFiles, SdfPath::AbsoluteRootPath()); if (!clipLayersAreValid || !_UsdUtilsStitchClipsTopologyImpl(topologyLayer, clipLayers)) { return false; } topologyLayer->Save(); return true; }
bool UsdUtilsStitchClips(const SdfLayerHandle& resultLayer, const _ClipFileVector& clipLayerFiles, const SdfPath& clipPath, const double startTimeCode, const double endTimeCode, const TfToken& clipSet) { // XXX: See comment in UsdUtilsStitchClipsTopology above. TF_PY_ALLOW_THREADS_IN_SCOPE(); // Prepare result layer for editing if (!_LayerIsWritable(resultLayer)) { return false; } else { resultLayer->Clear(); } // Prepare topology layer for editing, create if necessary bool topologyPreExisting = true; std::string topologyLayerId = UsdUtilsGenerateClipTopologyName(resultLayer->GetIdentifier()); SdfLayerRefPtr topologyLayer = SdfLayer::FindOrOpen(topologyLayerId); if (!topologyLayer) { topologyPreExisting = false; topologyLayer = SdfLayer::CreateNew(topologyLayerId); } if (!_LayerIsWritable(topologyLayer)) { return false; } else { topologyLayer->Clear(); } // Open all clip layers and validate clipPath SdfLayerRefPtrVector clipLayers; const bool clipLayersAreValid = _OpenClipLayers(&clipLayers, clipLayerFiles, clipPath); if (!clipLayersAreValid || !_UsdUtilsStitchClipsImpl(resultLayer, topologyLayer, clipLayers, clipPath, startTimeCode, endTimeCode, clipSet)) { if (!topologyPreExisting) { TfDeleteFile(topologyLayer->GetIdentifier()); } return false; } // Note that we don't apply edits until all other // actions have completed. topologyLayer->Save(); resultLayer->Save(); return true; }
/* static */ void UsdKatanaCache::_SetMutedLayers( const UsdStageRefPtr &stage, const std::string &layerRegex) { // Trace this function to track its performance TRACE_FUNCTION(); // Unmute layers that are currently muted, but not requested to be muted SdfLayerHandleVector stageLayers = stage->GetUsedLayers(); bool regexIsEmpty = layerRegex == "" || layerRegex == "^$"; // use a better regex library? regex_t regex; regcomp(®ex, layerRegex.c_str(), REG_EXTENDED); regmatch_t* rmatch = 0; TF_FOR_ALL(stageLayer, stageLayers) { SdfLayerHandle layer = *stageLayer; if (!layer) { continue; } std::string layerPath = layer->GetRepositoryPath(); const std::string layerIdentifier = layer->GetIdentifier(); bool match = false; if (!regexIsEmpty) { if (layer && !regexec( ®ex, layerIdentifier.c_str(), 0, rmatch, 0)) { match = true; } } if (!match && stage->IsLayerMuted(layerIdentifier)) { TF_DEBUG(USDKATANA_CACHE_RENDERER).Msg("{USD RENDER CACHE} " "Unmuting Layer: '%s'\n", layerIdentifier.c_str()); stage->UnmuteLayer(layerIdentifier); } if (match && !stage->IsLayerMuted(layerIdentifier)) { TF_DEBUG(USDKATANA_CACHE_RENDERER).Msg("{USD RENDER CACHE} " "Muting Layer: '%s'\n", layerIdentifier.c_str()); stage->MuteLayer(layerIdentifier); } }
void Sdf_ConnectionListEditor<ChildPolicy>::_OnEdit( SdfListOpType op, SdfSpecType specType, const std::vector<SdfPath>& oldItems, const std::vector<SdfPath>& newItems) const { if (op != SdfListOpTypeAdded and op != SdfListOpTypeExplicit) { return; } const SdfPath propertyPath = GetPath(); SdfLayerHandle layer = GetLayer(); const std::set<value_type> oldItemSet(oldItems.begin(), oldItems.end()); const std::set<value_type> newItemSet(newItems.begin(), newItems.end()); // Need to remove all children in oldItems that are not in newItems. std::vector<SdfPath> childrenToRemove; std::set_difference(oldItemSet.begin(), oldItemSet.end(), newItemSet.begin(), newItemSet.end(), std::back_inserter(childrenToRemove)); TF_FOR_ALL(child, childrenToRemove) { if (not Sdf_ChildrenUtils<ChildPolicy>::RemoveChild( layer, propertyPath, *child)) { const SdfPath specPath = ChildPolicy::GetChildPath(propertyPath, *child); TF_CODING_ERROR("Failed to remove spec at <%s>", specPath.GetText()); } } // Need to add all children in newItems that are not in oldItems. std::vector<SdfPath> childrenToAdd; std::set_difference(newItemSet.begin(), newItemSet.end(), oldItemSet.begin(), oldItemSet.end(), std::back_inserter(childrenToAdd)); TF_FOR_ALL(child, childrenToAdd) { const SdfPath specPath = ChildPolicy::GetChildPath(propertyPath, *child); if (layer->GetObjectAtPath(specPath)) { continue; } if (not Sdf_ChildrenUtils<ChildPolicy>::CreateSpec(layer, specPath, specType)) { TF_CODING_ERROR("Failed to create spec at <%s>", specPath.GetText()); } } }
string SdfComputeAssetPathRelativeToLayer( const SdfLayerHandle& anchor, const string& assetPath) { if (not anchor) { TF_CODING_ERROR("Invalid anchor layer"); return string(); } if (assetPath.empty()) { TF_CODING_ERROR("Layer path is empty"); return string(); } TRACE_FUNCTION(); ArResolver& resolver = ArGetResolver(); // Relative paths are resolved using the look-here-first scheme, in // which we first look relative to the layer, then fall back to search // path resolution. string finalLayerPath = anchor->ComputeAbsolutePath(assetPath); if (not SdfLayer::IsAnonymousLayerIdentifier(finalLayerPath)) { if (resolver.IsSearchPath(assetPath) and resolver.Resolve(finalLayerPath).empty()) return assetPath; } return finalLayerPath; }
static void _ProcessChildren( const TfToken& childrenField, const VtValue& srcChildrenValue, const VtValue& dstChildrenValue, const SdfLayerHandle& srcLayer, const SdfPath& srcPath, bool childrenInSrc, const SdfLayerHandle& dstLayer, const SdfPath& dstPath, bool childrenInDst, _CopyStack* copyStack) { typedef typename ChildPolicy::FieldType FieldType; typedef std::vector<FieldType> ChildrenVector; if (!TF_VERIFY(srcChildrenValue.IsHolding<ChildrenVector>() || srcChildrenValue.IsEmpty()) || !TF_VERIFY(dstChildrenValue.IsHolding<ChildrenVector>() || dstChildrenValue.IsEmpty())) { return; } const ChildrenVector emptyChildren; const ChildrenVector& srcChildren = srcChildrenValue.IsEmpty() ? emptyChildren : srcChildrenValue.UncheckedGet<ChildrenVector>(); const ChildrenVector& dstChildren = dstChildrenValue.IsEmpty() ? emptyChildren : dstChildrenValue.UncheckedGet<ChildrenVector>(); for (size_t i = 0; i < srcChildren.size(); ++i) { if (srcChildren[i].IsEmpty() || dstChildren[i].IsEmpty()) { continue; } const SdfPath srcChildPath = ChildPolicy::GetChildPath(srcPath, srcChildren[i]); const SdfPath dstChildPath = ChildPolicy::GetChildPath(dstPath, dstChildren[i]); copyStack->emplace_back(srcChildPath, dstChildPath); } // Add entries to the copy stack to mark the removal of child specs // in the destination layer that aren't included in the list of children // to copy. if (childrenInDst) { const VtValue oldDstChildrenValue = dstLayer->GetField(dstPath, childrenField); if (!TF_VERIFY(oldDstChildrenValue.IsHolding<ChildrenVector>())) { return; } for (const auto& oldDstChild : oldDstChildrenValue.UncheckedGet<ChildrenVector>()) { if (std::find(dstChildren.begin(), dstChildren.end(), oldDstChild) == dstChildren.end()) { const SdfPath oldDstChildPath = ChildPolicy::GetChildPath(dstPath, oldDstChild); copyStack->emplace_back(SdfPath(), oldDstChildPath); } } } }
SdfPathVector Sdf_MarkerUtils<Spec>::GetMarkerPaths(const Spec& owner) { SdfPathVector paths; const SdfLayerHandle layer = owner.GetLayer(); const SdfPathVector children = owner.template GetFieldAs<SdfPathVector>( _MarkerPolicy::GetChildFieldKey()); TF_FOR_ALL(path, children) { const SdfPath targetSpecPath = owner.GetPath().AppendTarget(*path); if (layer->HasField(targetSpecPath, SdfFieldKeys->Marker)) { paths.push_back(*path); } } return paths; }
void SdfFileFormat::_SetLayerData( const SdfLayerHandle& layer, SdfAbstractDataRefPtr& data) { // If layer initialization has not completed, then this // is being loaded as a new layer; otherwise we are loading // data into an existing layer. // // Note that this is an optional::bool and we are checking if it has // been set, not what its held value is. // const bool layerIsLoadingAsNew = !layer->_initializationWasSuccessful; if (layerIsLoadingAsNew) { layer->_SwapData(data); } else { layer->_SetData(data); } }
// Returns lists of value and children field names to be handled during // the copy process. The returned lists are sorted using the // TfTokenFastArbitraryLessThan comparator. static void _GetFieldNames( const SdfLayerHandle& layer, const SdfPath& path, std::vector<TfToken>* valueFields, std::vector<TfToken>* childrenFields) { const SdfSchemaBase& schema = layer->GetSchema(); const std::vector<TfToken> allFields = layer->ListFields(path); for (const TfToken& field : allFields) { if (schema.HoldsChildren(field)) { childrenFields->push_back(field); } else { valueFields->push_back(field); } } TfTokenFastArbitraryLessThan lessThan; std::sort(valueFields->begin(), valueFields->end(), lessThan); std::sort(childrenFields->begin(), childrenFields->end(), lessThan); }
bool UsdUtilsStitchClipsTemplate(const SdfLayerHandle& resultLayer, const SdfLayerHandle& topologyLayer, const SdfPath& clipPath, const std::string& templatePath, const double startTime, const double endTime, const double stride, const double activeOffset, const TfToken& clipSet) { // XXX: See comment in UsdUtilsStitchClipsTopology above. TF_PY_ALLOW_THREADS_IN_SCOPE(); if (!_LayerIsWritable(resultLayer)) { return false; } else { resultLayer->Clear(); } if (!topologyLayer) { return false; } // set prim level metadata auto prim = SdfCreatePrimInLayer(resultLayer, clipPath); const std::string topologyId = _GetRelativePathIfPossible(topologyLayer->GetIdentifier(), topologyLayer->GetRealPath(), resultLayer->GetRealPath()); // set root layer metadata _StitchClipsTopologySubLayerPath(resultLayer, topologyId); VtDictionary clipSetDict; clipSetDict[UsdClipsAPIInfoKeys->primPath] = clipPath.GetString(); clipSetDict[UsdClipsAPIInfoKeys->templateAssetPath] = templatePath; clipSetDict[UsdClipsAPIInfoKeys->templateStartTime] = startTime; clipSetDict[UsdClipsAPIInfoKeys->templateEndTime] = endTime; clipSetDict[UsdClipsAPIInfoKeys->templateStride] = stride; clipSetDict[UsdClipsAPIInfoKeys->manifestAssetPath] = SdfAssetPath(topologyId); if (activeOffset != std::numeric_limits<double>::max()) { clipSetDict[UsdClipsAPIInfoKeys->templateActiveOffset] = activeOffset; } VtDictionary clips; clips[clipSet] = clipSetDict; prim->SetInfo(UsdTokens->clips, VtValue::Take(clips)); resultLayer->SetStartTimeCode(startTime); resultLayer->SetEndTimeCode(endTime); resultLayer->Save(); return true; }
bool UsdMtlxFileFormat::ReadFromString( const SdfLayerBasePtr& layerBase, const std::string& str) const { TRACE_FUNCTION(); SdfLayerHandle layer = TfDynamic_cast<SdfLayerHandle>(layerBase); if (!TF_VERIFY(layer)) { return false; } auto stage = UsdStage::CreateInMemory(); if (!_Read(stage, [&str](mx::DocumentPtr d) { mx::readFromXmlString(d, str); })) { return false; } layer->TransferContent(stage->GetRootLayer()); return true; }
// Add a (field, value) entry to the list of fields to copy as directed by // the given policy. The value may be empty to indicate that the field // should be removed from the destination. static void _AddFieldValueToCopy( SdfSpecType specType, const TfToken& field, const SdfLayerHandle& srcLayer, const SdfPath& srcPath, bool fieldInSrc, const SdfLayerHandle& dstLayer, const SdfPath& dstPath, bool fieldInDst, const SdfShouldCopyValueFn& shouldCopyValue, _FieldValueList* valueList) { boost::optional<VtValue> value; if (shouldCopyValue( specType, field, srcLayer, srcPath, fieldInSrc, dstLayer, dstPath, fieldInDst, &value)) { valueList->emplace_back( field, value ? *value : srcLayer->GetField(srcPath, field)); } }
static void _AddNewSpecToLayer( const SdfLayerHandle& destLayer, const _SpecDataEntry& specData) { if (destLayer->HasSpec(specData.dstPath)) { return; } switch (specData.specType) { case SdfSpecTypeAttribute: _DoAddNewPropertySpec<Sdf_AttributeChildPolicy>(destLayer, specData); break; case SdfSpecTypeConnection: _DoAddNewSpec<Sdf_AttributeConnectionChildPolicy>(destLayer, specData); break; case SdfSpecTypeExpression: _DoAddNewSpec<Sdf_ExpressionChildPolicy>(destLayer, specData); break; case SdfSpecTypeMapper: _DoAddNewSpec<Sdf_MapperChildPolicy>(destLayer, specData); break; case SdfSpecTypeMapperArg: _DoAddNewSpec<Sdf_MapperArgChildPolicy>(destLayer, specData); break; case SdfSpecTypePrim: _DoAddNewPrimSpec(destLayer, specData); break; case SdfSpecTypeRelationship: _DoAddNewPropertySpec<Sdf_RelationshipChildPolicy>(destLayer, specData); break; case SdfSpecTypeRelationshipTarget: _DoAddNewSpec<Sdf_RelationshipTargetChildPolicy>(destLayer, specData); break; case SdfSpecTypeVariant: _DoAddNewSpec<Sdf_VariantChildPolicy>(destLayer, specData); break; case SdfSpecTypeVariantSet: _DoAddNewSpec<Sdf_VariantSetChildPolicy>(destLayer, specData); break; case SdfSpecTypePseudoRoot: case SdfSpecTypeUnknown: case SdfNumSpecTypes: break; } }
static void _RemoveSpecFromLayer( const SdfLayerHandle& dstLayer, const _SpecDataEntry& specData) { switch (dstLayer->GetSpecType(specData.dstPath)) { case SdfSpecTypeAttribute: _DoRemoveSpec<Sdf_AttributeChildPolicy>(dstLayer, specData); break; case SdfSpecTypeConnection: _DoRemoveSpec<Sdf_AttributeConnectionChildPolicy>(dstLayer, specData); break; case SdfSpecTypeExpression: _DoRemoveSpec<Sdf_ExpressionChildPolicy>(dstLayer, specData); break; case SdfSpecTypeMapper: _DoRemoveSpec<Sdf_MapperChildPolicy>(dstLayer, specData); break; case SdfSpecTypeMapperArg: _DoRemoveSpec<Sdf_MapperArgChildPolicy>(dstLayer, specData); break; case SdfSpecTypePrim: _DoRemoveSpec<Sdf_PrimChildPolicy>(dstLayer, specData); break; case SdfSpecTypeRelationship: _DoRemoveSpec<Sdf_RelationshipChildPolicy>(dstLayer, specData); break; case SdfSpecTypeRelationshipTarget: _DoRemoveSpec<Sdf_RelationshipTargetChildPolicy>(dstLayer, specData); break; case SdfSpecTypeVariant: _DoRemoveSpec<Sdf_VariantChildPolicy>(dstLayer, specData); break; case SdfSpecTypeVariantSet: _DoRemoveSpec<Sdf_VariantSetChildPolicy>(dstLayer, specData); break; case SdfSpecTypePseudoRoot: case SdfSpecTypeUnknown: case SdfNumSpecTypes: break; } }
Sdf_SubLayerListEditor::Sdf_SubLayerListEditor( const SdfLayerHandle& owner) : Parent(owner->GetPseudoRoot(), SdfFieldKeys->SubLayers, SdfListOpTypeOrdered) { }
static RootPrimsProxy _WrapGetRootPrims(const SdfLayerHandle& layer) { return RootPrimsProxy(layer->GetRootPrims(), "prim"); }
SdfAbstractDataConstPtr SdfFileFormat::_GetLayerData(const SdfLayerHandle& layer) { return layer->_GetData(); }
static bool _WrapIsMuted(const SdfLayerHandle &layer) { return layer->IsMuted(); }
bool UsdPrim::SetPayload(const SdfLayerHandle& layer, const SdfPath& primPath) const { return SetMetadata(SdfFieldKeys->Payload, SdfPayload(layer->GetIdentifier(), primPath)); }
bool SdfCopySpec( const SdfLayerHandle& srcLayer, const SdfPath& srcPath, const SdfLayerHandle& dstLayer, const SdfPath& dstPath, const SdfShouldCopyValueFn& shouldCopyValueFn, const SdfShouldCopyChildrenFn& shouldCopyChildrenFn) { if (!srcLayer || !dstLayer) { TF_CODING_ERROR("Invalid layer handle"); return false; } if (srcPath.IsEmpty() || dstPath.IsEmpty()) { TF_CODING_ERROR("Invalid empty path"); return false; } // Validate compatible source and destination path types. if ((srcPath.IsAbsoluteRootOrPrimPath() || srcPath.IsPrimVariantSelectionPath()) != (dstPath.IsAbsoluteRootOrPrimPath() || dstPath.IsPrimVariantSelectionPath()) || srcPath.IsPropertyPath() != dstPath.IsPropertyPath() || srcPath.IsTargetPath() != dstPath.IsTargetPath() || srcPath.IsMapperPath() != dstPath.IsMapperPath() || srcPath.IsMapperArgPath() != dstPath.IsMapperArgPath() || srcPath.IsExpressionPath() != dstPath.IsExpressionPath()) { TF_CODING_ERROR("Incompatible source and destination paths"); return false; } // For target paths (relationship targets and connections), verify the // destination spec already exists. See the documentation comment. if (dstPath.IsTargetPath() && !dstLayer->HasSpec(dstPath)) { TF_CODING_ERROR("Spec does not exist at destination target path"); return false; } // This function collects all of the data that will be copied for each // spec into this list, then applies it to the layer at the very end. // This allows us to do some analysis on the data first. _CopyEntryList dataToCopy; // Create a stack of source/dest copy requests, initially populated with // the passed parameters. The copy routine will add additional requests // as needed to handle children etc... and runs until the stack is empty. _CopyStack copyStack(1, _CopyStackEntry(srcPath, dstPath)); while (!copyStack.empty()) { const _CopyStackEntry toCopy = copyStack.front(); copyStack.pop_front(); // If the source path is empty, it indicates that the spec at the // destination path should be removed. Add an entry to the queue // to reflect that. if (toCopy.srcPath.IsEmpty()) { _SpecDataEntry removeEntry(toCopy.dstPath, SdfSpecTypeUnknown); dataToCopy.push_back(removeEntry); continue; } // Figure out the concrete type of the spec we're copying. The spec type // dictates copying behavior below. const SdfSpecType specType = srcLayer->GetSpecType(toCopy.srcPath); if (specType == SdfSpecTypeUnknown) { TF_CODING_ERROR("Cannot copy unknown spec at <%s> from layer <%s>", srcPath.GetText(), srcLayer->GetIdentifier().c_str()); return false; } _SpecDataEntry copyEntry(toCopy.dstPath, specType); // Determine what data is present for the current source and dest specs // and what needs to be copied. Divide the present fields into those // that contain values and those that index children specs. std::vector<TfToken> dstValueFields; std::vector<TfToken> dstChildrenFields; _GetFieldNames( dstLayer, toCopy.dstPath, &dstValueFields, &dstChildrenFields); std::vector<TfToken> srcValueFields; std::vector<TfToken> srcChildrenFields; _GetFieldNames( srcLayer, toCopy.srcPath, &srcValueFields, &srcChildrenFields); // From the list of value fields, retrieve all values that the copy // policy says we need to copy over to the destination. _ForEachField( srcValueFields, dstValueFields, [&](const TfToken& field, bool fieldInSrc, bool fieldInDst) { _AddFieldValueToCopy( specType, field, srcLayer, toCopy.srcPath, fieldInSrc, dstLayer, toCopy.dstPath, fieldInDst, shouldCopyValueFn, ©Entry.dataToCopy); }); // Add an entry for all of the data we're copying for this spec. dataToCopy.push_back(copyEntry); // Now add any children specs that need to be copied to our // copy stack. _ForEachField( srcChildrenFields, dstChildrenFields, [&](const TfToken& field, bool fieldInSrc, bool fieldInDst) { _ProcessChildField( field, srcLayer, toCopy.srcPath, fieldInSrc, dstLayer, toCopy.dstPath, fieldInDst, shouldCopyChildrenFn, ©Stack); }); } // Now that we have all the data we want to copy, set it into the // destination layer. SdfChangeBlock block; for (const _SpecDataEntry& specData : dataToCopy) { if (specData.specType == SdfSpecTypeUnknown) { _RemoveSpecFromLayer(dstLayer, specData); } else { _AddNewSpecToLayer(dstLayer, specData); } for (const _FieldValuePair& fieldValue : specData.dataToCopy) { dstLayer->SetField( specData.dstPath, fieldValue.first, fieldValue.second); } } return true; }
static void _ProcessChildField( const TfToken& childField, const SdfLayerHandle& srcLayer, const SdfPath& srcPath, bool childrenInSrc, const SdfLayerHandle& dstLayer, const SdfPath& dstPath, bool childrenInDst, const SdfShouldCopyChildrenFn& shouldCopyChildren, _CopyStack* copyStack) { boost::optional<VtValue> srcChildrenToCopy, dstChildrenToCopy; if (!shouldCopyChildren( childField, srcLayer, srcPath, childrenInSrc, dstLayer, dstPath, childrenInDst, &srcChildrenToCopy, &dstChildrenToCopy)) { return; } if (!srcChildrenToCopy || !dstChildrenToCopy) { srcChildrenToCopy = srcLayer->GetField(srcPath, childField); dstChildrenToCopy = srcChildrenToCopy; } const VtValue& srcChildren = *srcChildrenToCopy; const VtValue& dstChildren = *dstChildrenToCopy; if (childField == SdfChildrenKeys->ConnectionChildren) { _ProcessChildren<Sdf_AttributeConnectionChildPolicy>( childField, srcChildren, dstChildren, srcLayer, srcPath, childrenInSrc, dstLayer, dstPath, childrenInDst, copyStack); return; } if (childField == SdfChildrenKeys->MapperChildren) { _ProcessChildren<Sdf_MapperChildPolicy>( childField, srcChildren, dstChildren, srcLayer, srcPath, childrenInSrc, dstLayer, dstPath, childrenInDst, copyStack); return; } if (childField == SdfChildrenKeys->MapperArgChildren) { _ProcessChildren<Sdf_MapperArgChildPolicy>( childField, srcChildren, dstChildren, srcLayer, srcPath, childrenInSrc, dstLayer, dstPath, childrenInDst, copyStack); return; } if (childField == SdfChildrenKeys->ExpressionChildren) { _ProcessChildren<Sdf_ExpressionChildPolicy>( childField, srcChildren, dstChildren, srcLayer, srcPath, childrenInSrc, dstLayer, dstPath, childrenInDst, copyStack); return; } if (childField == SdfChildrenKeys->RelationshipTargetChildren) { _ProcessChildren<Sdf_RelationshipTargetChildPolicy>( childField, srcChildren, dstChildren, srcLayer, srcPath, childrenInSrc, dstLayer, dstPath, childrenInDst, copyStack); return; } if (childField == SdfChildrenKeys->VariantChildren) { _ProcessChildren<Sdf_VariantChildPolicy>( childField, srcChildren, dstChildren, srcLayer, srcPath, childrenInSrc, dstLayer, dstPath, childrenInDst, copyStack); return; } if (childField == SdfChildrenKeys->VariantSetChildren) { _ProcessChildren<Sdf_VariantSetChildPolicy>( childField, srcChildren, dstChildren, srcLayer, srcPath, childrenInSrc, dstLayer, dstPath, childrenInDst, copyStack); return; } if (childField == SdfChildrenKeys->PropertyChildren) { _ProcessChildren<Sdf_PropertyChildPolicy>( childField, srcChildren, dstChildren, srcLayer, srcPath, childrenInSrc, dstLayer, dstPath, childrenInDst, copyStack); return; } if (childField == SdfChildrenKeys->PrimChildren) { _ProcessChildren<Sdf_PrimChildPolicy>( childField, srcChildren, dstChildren, srcLayer, srcPath, childrenInSrc, dstLayer, dstPath, childrenInDst, copyStack); return; } TF_CODING_ERROR("Unknown child field '%s'", childField.GetText()); }
void Sdf_ConnectionListEditor<ChildPolicy>::_OnEditShared( SdfListOpType op, SdfSpecType specType, const std::vector<SdfPath>& oldItems, const std::vector<SdfPath>& newItems) const { // XXX The following code tries to manage lifetime of the target // specs associated with this list, but it slightly buggy: if // multiple lists mention the same target -- ex. if a target is // added, appended, and prepended -- then this proxy for a single // list has no way to know if the target also exists in those // other lists, and so it cannot mangae lifetime on its own. if (op == SdfListOpTypeOrdered || op == SdfListOpTypeDeleted) { // These ops do not affect target spec lifetime, so there's // nothing to do. return; } const SdfPath propertyPath = GetPath(); SdfLayerHandle layer = GetLayer(); const std::set<value_type> oldItemSet(oldItems.begin(), oldItems.end()); const std::set<value_type> newItemSet(newItems.begin(), newItems.end()); // Need to remove all children in oldItems that are not in newItems. std::vector<SdfPath> childrenToRemove; std::set_difference(oldItemSet.begin(), oldItemSet.end(), newItemSet.begin(), newItemSet.end(), std::back_inserter(childrenToRemove)); TF_FOR_ALL(child, childrenToRemove) { if (!Sdf_ChildrenUtils<ChildPolicy>::RemoveChild( layer, propertyPath, *child)) { // Some data backends procedurally generate the children specs based // on the listops as an optimization, so if we failed to remove a // child here, it could be that. If no spec is present, then we // consider things to be okay and do not issue an error. const SdfPath specPath = ChildPolicy::GetChildPath(propertyPath, *child); if (layer->GetObjectAtPath(specPath)) { TF_CODING_ERROR("Failed to remove spec at <%s>", specPath.GetText()); } } } // Need to add all children in newItems that are not in oldItems. std::vector<SdfPath> childrenToAdd; std::set_difference(newItemSet.begin(), newItemSet.end(), oldItemSet.begin(), oldItemSet.end(), std::back_inserter(childrenToAdd)); TF_FOR_ALL(child, childrenToAdd) { const SdfPath specPath = ChildPolicy::GetChildPath(propertyPath, *child); if (layer->GetObjectAtPath(specPath)) { continue; } if (!Sdf_ChildrenUtils<ChildPolicy>::CreateSpec(layer, specPath, specType)) { TF_CODING_ERROR("Failed to create spec at <%s>", specPath.GetText()); } } }