1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 //    names, trademarks, service marks, or product names of the Licensor
11 //    and its affiliates, except as required to comply with Section 4(c) of
12 //    the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 //     http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 /// \file PrimSpec.cpp
25 
26 #include "pxr/pxr.h"
27 #include "pxr/usd/sdf/primSpec.h"
28 #include "pxr/usd/sdf/accessorHelpers.h"
29 #include "pxr/usd/sdf/attributeSpec.h"
30 #include "pxr/usd/sdf/changeBlock.h"
31 #include "pxr/usd/sdf/childrenUtils.h"
32 #include "pxr/usd/sdf/layer.h"
33 #include "pxr/usd/sdf/listOpListEditor.h"
34 #include "pxr/usd/sdf/path.h"
35 #include "pxr/usd/sdf/propertySpec.h"
36 #include "pxr/usd/sdf/reference.h"
37 #include "pxr/usd/sdf/relationshipSpec.h"
38 #include "pxr/usd/sdf/schema.h"
39 #include "pxr/usd/sdf/variantSetSpec.h"
40 #include "pxr/usd/sdf/variantSpec.h"
41 
42 #include "pxr/base/tf/iterator.h"
43 #include "pxr/base/tf/ostreamMethods.h"
44 #include "pxr/base/tf/type.h"
45 #include "pxr/base/trace/trace.h"
46 
47 #include <ostream>
48 #include <utility>
49 #include <string>
50 #include <vector>
51 
52 using std::pair;
53 using std::string;
54 using std::vector;
55 
56 PXR_NAMESPACE_OPEN_SCOPE
57 
58 SDF_DEFINE_SPEC(SdfSchema, SdfSpecTypePrim, SdfPrimSpec, SdfSpec);
59 
60 // register types
TF_REGISTRY_FUNCTION(TfType)61 TF_REGISTRY_FUNCTION(TfType)
62 {
63     TfType::Define< SdfPrimSpecHandleVector >().
64         Alias( TfType::GetRoot(), "SdfPrimSpecHandleVector");
65     TfType::Define< SdfVariantSetSpecHandleMap >().
66         Alias( TfType::GetRoot(), "map<string, SdfVariantSetSpecHandle>");
67 }
68 
69 ////////////////////////////////////////////////////////////////////////
70 
71 SdfPrimSpecHandle
New(const SdfLayerHandle & parentLayer,const std::string & name,SdfSpecifier spec,const std::string & typeName)72 SdfPrimSpec::New(const SdfLayerHandle& parentLayer,
73                  const std::string& name, SdfSpecifier spec,
74                  const std::string& typeName)
75 {
76     TRACE_FUNCTION();
77 
78     return _New(parentLayer ? parentLayer->GetPseudoRoot() : TfNullPtr,
79                 TfToken(name), spec, TfToken(typeName));
80 }
81 
82 SdfPrimSpecHandle
New(const SdfPrimSpecHandle & parentPrim,const std::string & name,SdfSpecifier spec,const std::string & typeName)83 SdfPrimSpec::New(const SdfPrimSpecHandle& parentPrim,
84                  const std::string& name, SdfSpecifier spec,
85                  const std::string& typeName)
86 {
87     TRACE_FUNCTION();
88 
89     return _New(parentPrim, TfToken(name), spec, TfToken(typeName));
90 }
91 
92 SdfPrimSpecHandle
_New(const SdfPrimSpecHandle & parentPrim,const TfToken & name,SdfSpecifier spec,const TfToken & typeName)93 SdfPrimSpec::_New(const SdfPrimSpecHandle &parentPrim,
94                   const TfToken &name, SdfSpecifier spec,
95                   const TfToken &typeName)
96 {
97     SdfPrimSpec *parentPrimPtr = get_pointer(parentPrim);
98 
99     if (!parentPrimPtr) {
100         TF_CODING_ERROR("Cannot create prim '%s' because the parent prim is "
101                         "NULL",
102                         name.GetText());
103         return TfNullPtr;
104     }
105     if (!SdfPrimSpec::IsValidName(name)) {
106         TF_RUNTIME_ERROR("Cannot create prim '%s' because '%s' is not a valid "
107                          "name",
108                          parentPrimPtr->GetPath().AppendChild(name).GetText(),
109                          name.GetText());
110         return TfNullPtr;
111     }
112 
113     // Group all the edits in a single change block.
114     SdfChangeBlock block;
115 
116     // Use the special "pass" token if the caller tried to
117     // create a typeless def
118     TfToken type = (typeName.IsEmpty() && spec == SdfSpecifierDef)
119                    ? SdfTokens->AnyTypeToken : typeName;
120 
121     SdfLayerHandle layer = parentPrimPtr->GetLayer();
122     SdfPath childPath = parentPrimPtr->GetPath().AppendChild(name);
123 
124     // PrimSpecs are considered inert if their specifier is
125     // "over" and the type is not specified.
126     bool inert = (spec == SdfSpecifierOver) && type.IsEmpty();
127 
128     if (!Sdf_ChildrenUtils<Sdf_PrimChildPolicy>::CreateSpec(
129                 layer, childPath, SdfSpecTypePrim, inert)) {
130         return TfNullPtr;
131     }
132 
133     layer->SetField(childPath, SdfFieldKeys->Specifier, spec);
134     if (!type.IsEmpty()) {
135         layer->SetField(childPath, SdfFieldKeys->TypeName, type);
136     }
137 
138     return layer->GetPrimAtPath(childPath);
139 }
140 
141 bool
_ValidateEdit(const TfToken & key) const142 SdfPrimSpec::_ValidateEdit(const TfToken& key) const
143 {
144     if (_IsPseudoRoot()) {
145         TF_CODING_ERROR("Cannot edit %s on a pseudo-root", key.GetText());
146         return false;
147     }
148     else {
149         return true;
150     }
151 }
152 
153 //
154 // Name
155 //
156 
157 const std::string&
GetName() const158 SdfPrimSpec::GetName() const
159 {
160     return GetPath().GetName();
161 }
162 
163 TfToken
GetNameToken() const164 SdfPrimSpec::GetNameToken() const
165 {
166     return GetPath().GetNameToken();
167 }
168 
169 bool
CanSetName(const std::string & newName,std::string * whyNot) const170 SdfPrimSpec::CanSetName(const std::string& newName, std::string* whyNot) const
171 {
172     if (_IsPseudoRoot()) {
173         if (whyNot) {
174             *whyNot = "The pseudo-root cannot be renamed";
175         }
176         return false;
177     }
178 
179     return Sdf_ChildrenUtils<Sdf_PrimChildPolicy>::CanRename(
180         *this, TfToken(newName)).IsAllowed(whyNot);
181 }
182 
183 bool
SetName(const std::string & name,bool validate)184 SdfPrimSpec::SetName(const std::string& name, bool validate)
185 {
186     SdfChangeBlock changeBlock;
187 
188     const TfToken newName(name);
189     const TfToken oldName = GetNameToken();
190     if (!Sdf_ChildrenUtils<Sdf_PrimChildPolicy>::Rename(
191             *this, newName)) {
192         return false;
193     }
194 
195     if (newName == oldName) {
196         // Nothing to do; just early out.
197         return true;
198     }
199 
200     // Also update any references to this prim in the parent spec's
201     // name children order.
202     const SdfPath parentPath = GetPath().GetParentPath();
203     if (SdfPrimSpecHandle parentPrim = GetLayer()->GetPrimAtPath(parentPath)) {
204         SdfNameChildrenOrderProxy ordering = parentPrim->GetNameChildrenOrder();
205         if (!ordering.empty()) {
206             // If an entry for newName already exists in the reorder list,
207             // make sure we remove it first before attempting to fixup the
208             // oldName entry. This takes care of two issues:
209             //
210             //   1. Duplicate entries are not allowed in the reorder list. If
211             //      we didn't remove the entry, we'd get an error.
212             //   2. Renaming a prim should not affect its position in the
213             //      reorder list.
214             ordering.Remove(newName);
215             ordering.Replace(oldName, newName);
216         }
217     }
218 
219     return true;
220 }
221 
222 bool
IsValidName(const std::string & name)223 SdfPrimSpec::IsValidName(const std::string& name)
224 {
225     return Sdf_ChildrenUtils<Sdf_PrimChildPolicy>::IsValidName(name);
226 }
227 
228 //
229 // Namespace hierarchy
230 //
231 
232 bool
_IsPseudoRoot() const233 SdfPrimSpec::_IsPseudoRoot() const
234 {
235     return GetSpecType() == SdfSpecTypePseudoRoot;
236 }
237 
238 SdfPrimSpecHandle
GetNameRoot() const239 SdfPrimSpec::GetNameRoot() const
240 {
241     return GetLayer()->GetPseudoRoot();
242 }
243 
244 SdfPrimSpecHandle
GetNameParent() const245 SdfPrimSpec::GetNameParent() const
246 {
247     return GetPath().IsRootPrimPath() ?
248         SdfPrimSpecHandle() :
249         GetLayer()->GetPrimAtPath(GetPath().GetParentPath());
250 }
251 
252 SdfPrimSpecHandle
GetRealNameParent() const253 SdfPrimSpec::GetRealNameParent() const
254 {
255     return GetLayer()->GetPrimAtPath(GetPath().GetParentPath());
256 }
257 
258 SdfPrimSpec::NameChildrenView
GetNameChildren() const259 SdfPrimSpec::GetNameChildren() const
260 {
261     return NameChildrenView(GetLayer(), GetPath(),
262                             SdfChildrenKeys->PrimChildren);
263 }
264 
265 void
SetNameChildren(const SdfPrimSpecHandleVector & nameChildrenSpecs)266 SdfPrimSpec::SetNameChildren(const SdfPrimSpecHandleVector& nameChildrenSpecs)
267 {
268     Sdf_ChildrenUtils<Sdf_PrimChildPolicy>::SetChildren(
269             GetLayer(), GetPath(), nameChildrenSpecs);
270 }
271 
272 bool
InsertNameChild(const SdfPrimSpecHandle & child,int index)273 SdfPrimSpec::InsertNameChild(const SdfPrimSpecHandle& child, int index)
274 {
275     return Sdf_ChildrenUtils<Sdf_PrimChildPolicy>::InsertChild(
276             GetLayer(), GetPath(),  child, index);
277 }
278 
279 bool
RemoveNameChild(const SdfPrimSpecHandle & child)280 SdfPrimSpec::RemoveNameChild(const SdfPrimSpecHandle& child)
281 {
282     if (child->GetLayer() != GetLayer() ||
283         child->GetPath().GetParentPath() != GetPath()) {
284         TF_CODING_ERROR("Cannot remove child prim '%s' from parent '%s' "
285                         "because it is not a child of that prim",
286                         child->GetPath().GetText(),
287                         GetPath().GetText());
288         return false;
289     }
290 
291     return Sdf_ChildrenUtils<Sdf_PrimChildPolicy>::RemoveChild(
292             GetLayer(), GetPath(), child->GetNameToken());
293 }
294 
295 SdfNameChildrenOrderProxy
GetNameChildrenOrder() const296 SdfPrimSpec::GetNameChildrenOrder() const
297 {
298     return SdfGetNameOrderProxy(SdfCreateHandle(this), SdfFieldKeys->PrimOrder);
299 }
300 
301 bool
HasNameChildrenOrder() const302 SdfPrimSpec::HasNameChildrenOrder() const
303 {
304     return !GetNameChildrenOrder().empty();
305 }
306 
307 void
SetNameChildrenOrder(const std::vector<TfToken> & names)308 SdfPrimSpec::SetNameChildrenOrder(const std::vector<TfToken>& names)
309 {
310     GetNameChildrenOrder() = names;
311 }
312 
313 void
InsertInNameChildrenOrder(const TfToken & name,int index)314 SdfPrimSpec::InsertInNameChildrenOrder(const TfToken& name, int index)
315 {
316     GetNameChildrenOrder().Insert(index, name);
317 }
318 
319 void
RemoveFromNameChildrenOrder(const TfToken & name)320 SdfPrimSpec::RemoveFromNameChildrenOrder(const TfToken& name)
321 {
322     GetNameChildrenOrder().Remove(name);
323 }
324 
325 void
RemoveFromNameChildrenOrderByIndex(int index)326 SdfPrimSpec::RemoveFromNameChildrenOrderByIndex(int index)
327 {
328     GetNameChildrenOrder().Erase(index);
329 }
330 
331 void
ApplyNameChildrenOrder(std::vector<TfToken> * vec) const332 SdfPrimSpec::ApplyNameChildrenOrder(std::vector<TfToken>* vec) const
333 {
334     GetNameChildrenOrder().ApplyEditsToList(vec);
335 }
336 
337 //
338 // Properties
339 //
340 
341 SdfPrimSpec::PropertySpecView
GetProperties() const342 SdfPrimSpec::GetProperties() const
343 {
344     return PropertySpecView(
345         GetLayer(), GetPath(), SdfChildrenKeys->PropertyChildren);
346 }
347 
348 void
SetProperties(const SdfPropertySpecHandleVector & propertySpecs)349 SdfPrimSpec::SetProperties(const SdfPropertySpecHandleVector& propertySpecs)
350 {
351     if (!_ValidateEdit(SdfChildrenKeys->PropertyChildren)) {
352         return;
353     }
354 
355     Sdf_ChildrenUtils<Sdf_PropertyChildPolicy>::SetChildren(
356         GetLayer(), GetPath(), propertySpecs);
357 }
358 
359 bool
InsertProperty(const SdfPropertySpecHandle & property,int index)360 SdfPrimSpec::InsertProperty(const SdfPropertySpecHandle& property, int index)
361 {
362     if (!_ValidateEdit(SdfChildrenKeys->PropertyChildren)) {
363         return false;
364     }
365 
366     return Sdf_ChildrenUtils<Sdf_PropertyChildPolicy>::InsertChild(
367         GetLayer(), GetPath(), property, index);
368 }
369 
370 void
RemoveProperty(const SdfPropertySpecHandle & property)371 SdfPrimSpec::RemoveProperty(const SdfPropertySpecHandle& property)
372 {
373     if (!_ValidateEdit(SdfChildrenKeys->PropertyChildren)) {
374         return;
375     }
376 
377     if (property->GetLayer() != GetLayer() ||
378             property->GetPath().GetParentPath() != GetPath()) {
379         TF_CODING_ERROR("Cannot remove property '%s' from prim '%s' because it "
380                         "does not belong to that prim",
381                         property->GetPath().GetText(),
382                         GetPath().GetText());
383         return;
384     }
385 
386     Sdf_ChildrenUtils<Sdf_PropertyChildPolicy>::RemoveChild(
387             GetLayer(), GetPath(), property->GetNameToken());
388 }
389 
390 SdfPrimSpec::AttributeSpecView
GetAttributes() const391 SdfPrimSpec::GetAttributes() const
392 {
393     return AttributeSpecView(GetLayer(), GetPath(),
394                              SdfChildrenKeys->PropertyChildren);
395 }
396 
397 SdfPrimSpec::RelationshipSpecView
GetRelationships() const398 SdfPrimSpec::GetRelationships() const
399 {
400     return RelationshipSpecView(
401         GetLayer(), GetPath(), SdfChildrenKeys->PropertyChildren);
402 }
403 
404 SdfPropertyOrderProxy
GetPropertyOrder() const405 SdfPrimSpec::GetPropertyOrder() const
406 {
407     return SdfGetNameOrderProxy(
408         SdfCreateHandle(this), SdfFieldKeys->PropertyOrder);
409 }
410 
411 bool
HasPropertyOrder() const412 SdfPrimSpec::HasPropertyOrder() const
413 {
414     return !GetPropertyOrder().empty();
415 }
416 
417 void
SetPropertyOrder(const std::vector<TfToken> & names)418 SdfPrimSpec::SetPropertyOrder(const std::vector<TfToken>& names)
419 {
420     if (_ValidateEdit(SdfChildrenKeys->PropertyChildren)) {
421         GetPropertyOrder() = names;
422     }
423 }
424 
425 void
InsertInPropertyOrder(const TfToken & name,int index)426 SdfPrimSpec::InsertInPropertyOrder(const TfToken& name, int index)
427 {
428     if (_ValidateEdit(SdfChildrenKeys->PropertyChildren)) {
429         GetPropertyOrder().Insert(index, name);
430     }
431 }
432 
433 void
RemoveFromPropertyOrder(const TfToken & name)434 SdfPrimSpec::RemoveFromPropertyOrder(const TfToken& name)
435 {
436     if (_ValidateEdit(SdfChildrenKeys->PropertyChildren)) {
437         GetPropertyOrder().Remove(name);
438     }
439 }
440 
441 void
RemoveFromPropertyOrderByIndex(int index)442 SdfPrimSpec::RemoveFromPropertyOrderByIndex(int index)
443 {
444     if (_ValidateEdit(SdfChildrenKeys->PropertyChildren)) {
445         GetPropertyOrder().Erase(index);
446     }
447 }
448 
449 void
ApplyPropertyOrder(std::vector<TfToken> * vec) const450 SdfPrimSpec::ApplyPropertyOrder(std::vector<TfToken>* vec) const
451 {
452     if (_ValidateEdit(SdfChildrenKeys->PropertyChildren)) {
453         GetPropertyOrder().ApplyEditsToList(vec);
454     }
455 }
456 
457 //
458 // Lookup
459 //
460 
461 SdfSpecHandle
GetObjectAtPath(const SdfPath & path) const462 SdfPrimSpec::GetObjectAtPath(const SdfPath& path) const
463 {
464     if (path.IsEmpty()) {
465         TF_CODING_ERROR("Cannot get object at the empty path");
466         return TfNullPtr;
467     }
468     const SdfPath absPath = path.MakeAbsolutePath(GetPath());
469     return GetLayer()->GetObjectAtPath(absPath);
470 }
471 
472 SdfPrimSpecHandle
GetPrimAtPath(const SdfPath & path) const473 SdfPrimSpec::GetPrimAtPath(const SdfPath& path) const
474 {
475     if (path.IsEmpty()) {
476         TF_CODING_ERROR("Cannot get prim at the empty path");
477         return TfNullPtr;
478     }
479     const SdfPath absPath = path.MakeAbsolutePath(GetPath());
480     return GetLayer()->GetPrimAtPath(absPath);
481 }
482 
483 SdfPropertySpecHandle
GetPropertyAtPath(const SdfPath & path) const484 SdfPrimSpec::GetPropertyAtPath(const SdfPath& path) const
485 {
486     if (path.IsEmpty()) {
487         TF_CODING_ERROR("Cannot get property at the empty path");
488         return TfNullPtr;
489     }
490     const SdfPath absPath = path.MakeAbsolutePath(GetPath());
491     return GetLayer()->GetPropertyAtPath(absPath);
492 }
493 
494 SdfAttributeSpecHandle
GetAttributeAtPath(const SdfPath & path) const495 SdfPrimSpec::GetAttributeAtPath(const SdfPath& path) const
496 {
497     if (path.IsEmpty()) {
498         TF_CODING_ERROR("Cannot get attribute at the empty path");
499         return TfNullPtr;
500     }
501     const SdfPath absPath = path.MakeAbsolutePath(GetPath());
502     return GetLayer()->GetAttributeAtPath(absPath);
503 }
504 
505 SdfRelationshipSpecHandle
GetRelationshipAtPath(const SdfPath & path) const506 SdfPrimSpec::GetRelationshipAtPath(const SdfPath& path) const
507 {
508     if (path.IsEmpty()) {
509         TF_CODING_ERROR("Cannot get relationship at the empty path");
510         return TfNullPtr;
511     }
512     const SdfPath absPath = path.MakeAbsolutePath(GetPath());
513     return GetLayer()->GetRelationshipAtPath(absPath);
514 }
515 
516 //
517 // Metadata
518 //
519 
520 // Initialize accessor helper macros to associate with this class and use
521 // member function _ValidateEdit as access predicate
522 #define SDF_ACCESSOR_CLASS                   SdfPrimSpec
523 #define SDF_ACCESSOR_READ_PREDICATE(key_)    SDF_NO_PREDICATE
524 #define SDF_ACCESSOR_WRITE_PREDICATE(key_)   _ValidateEdit(key_)
525 
526 SDF_DEFINE_GET(TypeName, SdfFieldKeys->TypeName, TfToken)
527 
528 SDF_DEFINE_GET_SET(Comment,            SdfFieldKeys->Comment,       std::string)
529 SDF_DEFINE_GET_SET(Documentation,      SdfFieldKeys->Documentation, std::string)
530 SDF_DEFINE_GET_SET(Hidden,             SdfFieldKeys->Hidden,        bool)
531 SDF_DEFINE_GET_SET(SymmetryFunction,   SdfFieldKeys->SymmetryFunction, TfToken)
532 SDF_DEFINE_GET_SET(SymmetricPeer,      SdfFieldKeys->SymmetricPeer, std::string)
533 SDF_DEFINE_GET_SET(Prefix,             SdfFieldKeys->Prefix,        std::string)
534 SDF_DEFINE_GET_SET(Suffix,             SdfFieldKeys->Suffix,        std::string)
535 
536 SDF_DEFINE_GET_SET(PrefixSubstitutions,  SdfFieldKeys->PrefixSubstitutions,
537                    VtDictionary)
538 SDF_DEFINE_GET_SET(SuffixSubstitutions,  SdfFieldKeys->SuffixSubstitutions,
539                    VtDictionary)
540 
541 SDF_DEFINE_GET_SET_HAS_CLEAR(Active,         SdfFieldKeys->Active,       bool)
542 SDF_DEFINE_GET_SET_HAS_CLEAR(Kind,           SdfFieldKeys->Kind,    TfToken)
543 SDF_DEFINE_GET_SET_HAS_CLEAR(Instanceable,   SdfFieldKeys->Instanceable, bool)
544 
545 SDF_DEFINE_TYPED_GET_SET(Specifier,  SdfFieldKeys->Specifier,
546                          SdfSpecifier,  SdfSpecifier)
547 SDF_DEFINE_TYPED_GET_SET(Permission, SdfFieldKeys->Permission,
548                          SdfPermission, SdfPermission)
549 
550 SDF_DEFINE_DICTIONARY_GET_SET(GetSymmetryArguments,
551                               SetSymmetryArgument,
552                               SdfFieldKeys->SymmetryArguments);
553 SDF_DEFINE_DICTIONARY_GET_SET(GetCustomData,
554                               SetCustomData,
555                               SdfFieldKeys->CustomData);
556 SDF_DEFINE_DICTIONARY_GET_SET(GetAssetInfo,
557                               SetAssetInfo,
558                               SdfFieldKeys->AssetInfo);
559 
560 // Clean up macro shenanigans
561 #undef SDF_ACCESSOR_CLASS
562 #undef SDF_ACCESSOR_READ_PREDICATE
563 #undef SDF_ACCESSOR_WRITE_PREDICATE
564 
565 void
SetTypeName(const std::string & value)566 SdfPrimSpec::SetTypeName(const std::string& value)
567 {
568     if (value.empty() && GetSpecifier() != SdfSpecifierOver) {
569         TF_CODING_ERROR("Cannot set empty type name on prim '%s'",
570                         GetPath().GetText());
571     } else {
572         if (_ValidateEdit(SdfFieldKeys->TypeName)) {
573             SetField(SdfFieldKeys->TypeName, TfToken(value));
574         }
575     }
576 }
577 
578 //
579 // Inherits
580 //
581 
582 SdfInheritsProxy
GetInheritPathList() const583 SdfPrimSpec::GetInheritPathList() const
584 {
585     return SdfGetPathEditorProxy(
586         SdfCreateHandle(this), SdfFieldKeys->InheritPaths);
587 }
588 
589 bool
HasInheritPaths() const590 SdfPrimSpec::HasInheritPaths() const
591 {
592     return GetInheritPathList().HasKeys();
593 }
594 
595 void
ClearInheritPathList()596 SdfPrimSpec::ClearInheritPathList()
597 {
598     if (_ValidateEdit(SdfFieldKeys->InheritPaths)) {
599         GetInheritPathList().ClearEdits();
600     }
601 }
602 
603 //
604 // Specializes
605 //
606 
607 SdfSpecializesProxy
GetSpecializesList() const608 SdfPrimSpec::GetSpecializesList() const
609 {
610     return SdfGetPathEditorProxy(
611         SdfCreateHandle(this), SdfFieldKeys->Specializes);
612 }
613 
614 bool
HasSpecializes() const615 SdfPrimSpec::HasSpecializes() const
616 {
617     return GetSpecializesList().HasKeys();
618 }
619 
620 void
ClearSpecializesList()621 SdfPrimSpec::ClearSpecializesList()
622 {
623     if (_ValidateEdit(SdfFieldKeys->Specializes)) {
624         GetSpecializesList().ClearEdits();
625     }
626 }
627 
628 //
629 // Payloads
630 //
631 
632 SdfPayloadsProxy
GetPayloadList() const633 SdfPrimSpec::GetPayloadList() const
634 {
635     return SdfGetPayloadEditorProxy(
636         SdfCreateHandle(this), SdfFieldKeys->Payload);
637 }
638 
639 bool
HasPayloads() const640 SdfPrimSpec::HasPayloads() const
641 {
642     return GetPayloadList().HasKeys();
643 }
644 
645 void
ClearPayloadList()646 SdfPrimSpec::ClearPayloadList()
647 {
648     if (_ValidateEdit(SdfFieldKeys->Payload)) {
649         GetPayloadList().ClearEdits();
650     }
651 }
652 
653 //
654 // References
655 //
656 
657 SdfReferencesProxy
GetReferenceList() const658 SdfPrimSpec::GetReferenceList() const
659 {
660     return SdfGetReferenceEditorProxy(
661         SdfCreateHandle(this), SdfFieldKeys->References);
662 }
663 
664 bool
HasReferences() const665 SdfPrimSpec::HasReferences() const
666 {
667     return GetReferenceList().HasKeys();
668 }
669 
670 void
ClearReferenceList()671 SdfPrimSpec::ClearReferenceList()
672 {
673     if (_ValidateEdit(SdfFieldKeys->References)) {
674         GetReferenceList().ClearEdits();
675     }
676 }
677 
678 //
679 // Variants
680 //
681 
682 SdfVariantSetNamesProxy
GetVariantSetNameList() const683 SdfPrimSpec::GetVariantSetNameList() const
684 {
685     boost::shared_ptr<Sdf_ListEditor<SdfNameKeyPolicy> > editor(
686             new Sdf_ListOpListEditor<SdfNameKeyPolicy>(
687                 SdfCreateHandle(this), SdfFieldKeys->VariantSetNames));
688     return SdfVariantSetNamesProxy(editor);
689 }
690 
691 bool
HasVariantSetNames() const692 SdfPrimSpec::HasVariantSetNames() const
693 {
694     return GetVariantSetNameList().HasKeys();
695 }
696 
697 std::vector<std::string>
GetVariantNames(const std::string & name) const698 SdfPrimSpec::GetVariantNames(const std::string& name) const
699 {
700     std::vector<std::string> variantNames;
701 
702     // Neither the pseudo root nor variants can have variant sets.
703     if (_IsPseudoRoot() || !GetPath().IsPrimPath()) {
704         return std::vector<std::string>();
705     }
706     SdfPath variantSetPath = GetPath().AppendVariantSelection(name, "");
707     std::vector<TfToken> variantNameTokens =
708         GetLayer()->GetFieldAs<std::vector<TfToken> >(variantSetPath,
709             SdfChildrenKeys->VariantChildren);
710 
711     variantNames.reserve(variantNameTokens.size());
712     TF_FOR_ALL(i, variantNameTokens) {
713         variantNames.push_back(i->GetString());
714     }
715 
716     return variantNames;
717 }
718 
719 SdfVariantSetsProxy
GetVariantSets() const720 SdfPrimSpec::GetVariantSets() const
721 {
722     return SdfVariantSetsProxy(SdfVariantSetView(GetLayer(),
723             GetPath(), SdfChildrenKeys->VariantSetChildren),
724             "variant sets", SdfVariantSetsProxy::CanErase);
725 }
726 
727 void
RemoveVariantSet(const std::string & name)728 SdfPrimSpec::RemoveVariantSet(const std::string& name)
729 {
730     if (_ValidateEdit(SdfChildrenKeys->VariantSetChildren)) {
731         GetVariantSets().erase(name);
732     }
733 }
734 
735 SdfVariantSelectionProxy
GetVariantSelections() const736 SdfPrimSpec::GetVariantSelections() const
737 {
738     if (!_IsPseudoRoot()) {
739         return SdfVariantSelectionProxy(
740             SdfCreateHandle(this), SdfFieldKeys->VariantSelection);
741     }
742     else {
743         return SdfVariantSelectionProxy();
744     }
745 }
746 
747 void
SetVariantSelection(const std::string & variantSetName,const std::string & variantName)748 SdfPrimSpec::SetVariantSelection(const std::string& variantSetName,
749                             const std::string& variantName)
750 {
751     if (_ValidateEdit(SdfFieldKeys->VariantSelection)) {
752         SdfVariantSelectionProxy proxy = GetVariantSelections();
753         if (proxy) {
754             if (variantName.empty()) {
755                 proxy.erase(variantSetName);
756             }
757             else {
758                 SdfChangeBlock block;
759                 proxy[variantSetName] = variantName;
760             }
761         }
762     }
763 }
764 
765 void
BlockVariantSelection(const std::string & variantSetName)766 SdfPrimSpec::BlockVariantSelection(const std::string& variantSetName)
767 {
768     if (_ValidateEdit(SdfFieldKeys->VariantSelection)) {
769         SdfVariantSelectionProxy proxy = GetVariantSelections();
770         if (proxy) {
771             SdfChangeBlock block;
772             proxy[variantSetName] = std::string();
773         }
774     }
775 }
776 
777 //
778 // Relocates
779 //
780 
781 SdfRelocatesMapProxy
GetRelocates() const782 SdfPrimSpec::GetRelocates() const
783 {
784     if (!_IsPseudoRoot()) {
785         return SdfRelocatesMapProxy(
786             SdfCreateHandle(this), SdfFieldKeys->Relocates);
787     }
788     else {
789         return SdfRelocatesMapProxy();
790     }
791 }
792 
793 void
SetRelocates(const SdfRelocatesMap & newMap)794 SdfPrimSpec::SetRelocates(const SdfRelocatesMap& newMap)
795 {
796     if (_ValidateEdit(SdfFieldKeys->Relocates)) {
797         GetRelocates() = newMap;
798     }
799 }
800 
801 bool
HasRelocates() const802 SdfPrimSpec::HasRelocates() const
803 {
804     return HasField(SdfFieldKeys->Relocates);
805 }
806 
807 void
ClearRelocates()808 SdfPrimSpec::ClearRelocates()
809 {
810     if (_ValidateEdit(SdfFieldKeys->Relocates)) {
811         ClearField(SdfFieldKeys->Relocates);
812     }
813 }
814 
815 //
816 // Utilities
817 //
818 
819 static bool
_FindOrCreateVariantSpec(SdfLayer * layer,const SdfPath & vsPath)820 _FindOrCreateVariantSpec(SdfLayer *layer, const SdfPath &vsPath)
821 {
822     SdfVariantSetSpecHandle varSetSpec;
823 
824     SdfPrimSpecHandle primSpec = layer->GetPrimAtPath(vsPath.GetParentPath());
825     if (!TF_VERIFY(primSpec)) {
826         return false;
827     }
828 
829     pair<string, string> varSel = vsPath.GetVariantSelection();
830 
831     // Try to find existing variant set.
832     const SdfVariantSetsProxy &variantSets = primSpec->GetVariantSets();
833     TF_FOR_ALL(varSetIt, variantSets) {
834         if (varSetIt->first == varSel.first) {
835             varSetSpec = varSetIt->second;
836             break;
837         }
838     }
839 
840     // Create a new variant set spec and add it to the variant set list.
841     if (!varSetSpec) {
842         if ((varSetSpec = SdfVariantSetSpec::New(primSpec, varSel.first)))
843             primSpec->GetVariantSetNameList().Prepend(varSel.first);
844     }
845 
846     if (!TF_VERIFY(varSetSpec, "Failed to create variant set for '%s' in @%s@",
847                    vsPath.GetText(), layer->GetIdentifier().c_str())) {
848         return false;
849     }
850 
851     // Now try to find an existing variant with the requested name.
852     TF_FOR_ALL(it, varSetSpec->GetVariants()) {
853         if ((*it)->GetName() == varSel.second) {
854             return true;
855         }
856     }
857 
858     return static_cast<bool>(SdfVariantSpec::New(varSetSpec, varSel.second));
859 }
860 
861 static bool
_IsValidPath(const SdfPath & path)862 _IsValidPath(const SdfPath& path)
863 {
864     // Can't use SdfCreatePrimInLayer with non-prim, non-variant paths.
865     if (!path.IsAbsoluteRootOrPrimPath() &&
866         !path.IsPrimVariantSelectionPath()) {
867         return false;
868     }
869 
870     // SdfPath says paths like /A/B{v=} are prim variant selection paths, but
871     // such paths identify variant sets, *not* variant prims. So, we need
872     // to check for this.
873     //
874     // We also need to check for paths like /A/B{v=}C, which are not valid
875     // prim paths.
876     //
877     // XXX: Perhaps these conditions should be encoded in SdfPath itself?
878     if (path.ContainsPrimVariantSelection()) {
879         for (SdfPath p = path.MakeAbsolutePath(SdfPath::AbsoluteRootPath());
880              p != SdfPath::AbsoluteRootPath(); p = p.GetParentPath()) {
881 
882             const pair<string, string> varSel = p.GetVariantSelection();
883             if (!varSel.first.empty() && varSel.second.empty()) {
884                 return false;
885             }
886         }
887     }
888 
889     return true;
890 }
891 
892 namespace {
893 
894 // This structure exists so that we can support relative paths to
895 // SdfCreatePrimInLayer/SdfJustCreatePrimInLayer without doing any path copies
896 // or refcount operations in the common case where we are given an absolute
897 // path.
898 struct _AbsPathHelper
899 {
900     // Construct with \p inPath.  If \p inPath is an absolute path, then
901     // GetAbsPath() returns \p inPath.  Otherwise \p inPath is made absolute by
902     // MakeAbsolutePath(SdfPath::AbsoluteRootPath()), stored in a member
903     // variable and returned by GetAbsPath().
_AbsPathHelper__anon9ac8623f0111::_AbsPathHelper904     explicit _AbsPathHelper(SdfPath const &inPath)
905         : _inPath(inPath) {
906         if (ARCH_LIKELY(_inPath.IsAbsolutePath())) {
907             _absPath = &_inPath;
908         }
909         else {
910             _tmpPath = _inPath.MakeAbsolutePath(SdfPath::AbsoluteRootPath());
911             _absPath = &_tmpPath;
912         }
913     }
914     explicit _AbsPathHelper(SdfPath &&inPath) = delete;
GetAbsPath__anon9ac8623f0111::_AbsPathHelper915     inline SdfPath const &GetAbsPath() const {
916         return *_absPath;
917     }
GetOriginalPath__anon9ac8623f0111::_AbsPathHelper918     inline SdfPath const &GetOriginalPath() const {
919         return _inPath;
920     }
921 private:
922     SdfPath const &_inPath;
923     SdfPath const *_absPath;  // points to either _inPath or _tmpPath.
924     SdfPath _tmpPath;
925 };
926 
927 } // anon
928 
929 bool
Sdf_UncheckedCreatePrimInLayer(SdfLayer * layerPtr,const SdfPath & primPath)930 Sdf_UncheckedCreatePrimInLayer(
931     SdfLayer *layerPtr, const SdfPath& primPath)
932 {
933     // If a prim already exists then just return it.
934     if (layerPtr->HasSpec(primPath)) {
935         return true;
936     }
937 
938     SdfPathVector ancestors;
939     ancestors.reserve(primPath.GetPathElementCount());
940 
941     bool maybeVariantSelPaths = primPath.ContainsPrimVariantSelection();
942     SdfPath path = primPath;
943     do {
944         ancestors.emplace_back(std::move(path));
945         path = ancestors.back().GetParentPath();
946     } while (!layerPtr->HasSpec(path));
947 
948     // Create each prim from root-most to the prim at primPath.
949     while (!ancestors.empty()) {
950         SdfPath ancPath = std::move(ancestors.back());
951         ancestors.pop_back();
952         if (maybeVariantSelPaths && ancPath.IsPrimVariantSelectionPath()) {
953             // Variant selection case.
954             if (!_FindOrCreateVariantSpec(layerPtr, ancPath)) {
955                 return false;
956             }
957         } else {
958             // Ordinary prim child case.
959             if (ARCH_UNLIKELY(
960                     !Sdf_ChildrenUtils<Sdf_PrimChildPolicy>::CreateSpec(
961                         layerPtr, ancPath, SdfSpecTypePrim, /*inert=*/true))) {
962                 TF_RUNTIME_ERROR("Failed to create prim at path '%s' in "
963                                  "layer @%s@", ancPath.GetText(),
964                                  layerPtr->GetIdentifier().c_str());
965                 return false;
966             }
967         }
968     }
969     return true;
970 }
971 
972 static inline bool
Sdf_CanCreatePrimInLayer(SdfLayer * layer,_AbsPathHelper const & absPath)973 Sdf_CanCreatePrimInLayer(SdfLayer *layer, _AbsPathHelper const &absPath)
974 {
975     SdfPath const &path = absPath.GetAbsPath();
976 
977     if (ARCH_UNLIKELY(!_IsValidPath(path))) {
978         TF_CODING_ERROR("Cannot create prim at path '%s' because it is not a "
979                         "valid prim or prim variant selection path",
980                         absPath.GetOriginalPath().GetText());
981         return false;
982     }
983 
984     if (ARCH_UNLIKELY(!layer)) {
985         TF_CODING_ERROR("Cannot create prim at path '%s' in null or expired "
986                         "layer", absPath.GetOriginalPath().GetText());
987         return false;
988     }
989 
990     return true;
991 }
992 
993 SdfPrimSpecHandle
SdfCreatePrimInLayer(const SdfLayerHandle & layer,const SdfPath & primPath)994 SdfCreatePrimInLayer(const SdfLayerHandle& layer, const SdfPath& primPath)
995 {
996     const _AbsPathHelper abs(primPath);
997     SdfLayer *layerPtr = get_pointer(layer);
998     if (Sdf_CanCreatePrimInLayer(layerPtr, abs)) {
999         SdfChangeBlock changeBlock;
1000         SdfPath const &absPath = abs.GetAbsPath();
1001         if (Sdf_UncheckedCreatePrimInLayer(layerPtr, absPath)) {
1002             return layer->GetPrimAtPath(absPath);
1003         }
1004     }
1005     return TfNullPtr;
1006 }
1007 
1008 bool
SdfJustCreatePrimInLayer(const SdfLayerHandle & layer,const SdfPath & primPath)1009 SdfJustCreatePrimInLayer(const SdfLayerHandle& layer, const SdfPath& primPath)
1010 {
1011     const _AbsPathHelper abs(primPath);
1012     SdfLayer *layerPtr = get_pointer(layer);
1013     if (Sdf_CanCreatePrimInLayer(layerPtr, abs)) {
1014         SdfChangeBlock changeBlock;
1015         return Sdf_UncheckedCreatePrimInLayer(layerPtr, abs.GetAbsPath());
1016     }
1017     return false;
1018 }
1019 
1020 PXR_NAMESPACE_CLOSE_SCOPE
1021