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