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 AttributeSpec.cpp
25
26 #include "pxr/pxr.h"
27 #include "pxr/usd/sdf/attributeSpec.h"
28 #include "pxr/usd/sdf/accessorHelpers.h"
29 #include "pxr/usd/sdf/changeBlock.h"
30 #include "pxr/usd/sdf/childrenUtils.h"
31 #include "pxr/usd/sdf/layer.h"
32 #include "pxr/usd/sdf/primSpec.h"
33 #include "pxr/usd/sdf/relationshipSpec.h"
34 #include "pxr/usd/sdf/schema.h"
35 #include "pxr/usd/sdf/types.h"
36
37 #include "pxr/base/tf/type.h"
38 #include "pxr/base/tf/ostreamMethods.h"
39 #include "pxr/base/trace/trace.h"
40
41 PXR_NAMESPACE_OPEN_SCOPE
42
43 SDF_DEFINE_SPEC(
44 SdfSchema, SdfSpecTypeAttribute, SdfAttributeSpec, SdfPropertySpec);
45
46 SdfAttributeSpecHandle
New(const SdfPrimSpecHandle & owner,const std::string & name,const SdfValueTypeName & typeName,SdfVariability variability,bool custom)47 SdfAttributeSpec::New(
48 const SdfPrimSpecHandle& owner,
49 const std::string& name,
50 const SdfValueTypeName& typeName,
51 SdfVariability variability,
52 bool custom)
53 {
54 TRACE_FUNCTION();
55
56 SdfAttributeSpecHandle result;
57
58 SdfPrimSpec *ownerPtr = get_pointer(owner);
59
60 if (!ownerPtr) {
61 TF_CODING_ERROR("Cannot create an SdfAttributeSpec with a null owner");
62 return result;
63 }
64
65 const SdfPath attrPath = ownerPtr->GetPath().AppendProperty(TfToken(name));
66 if (ARCH_UNLIKELY(attrPath.IsEmpty())) {
67 // This can happen if the owner is the pseudo-root '/', or if the passed
68 // name was not a valid property name. Give specific error messages in
69 // these cases.
70 if (!Sdf_ChildrenUtils<Sdf_AttributeChildPolicy>::IsValidName(name)) {
71 TF_CODING_ERROR(
72 "Cannot create attribute spec on <%s> with invalid name '%s'",
73 ownerPtr->GetPath().GetText(), name.c_str());
74 }
75 else if (ownerPtr->GetPath() == SdfPath::AbsoluteRootPath()) {
76 TF_CODING_ERROR(
77 "Cannot create attribute spec '%s' on the pseudo-root '/'",
78 name.c_str());
79 }
80 else {
81 TF_CODING_ERROR(
82 "Cannot create attribute spec '%s' on <%s>",
83 name.c_str(), ownerPtr->GetPath().GetText());
84 }
85 return result;
86 }
87
88 if (!typeName) {
89 TF_CODING_ERROR("Cannot create attribute spec <%s> with invalid type",
90 attrPath.GetText());
91 return result;
92 }
93
94 const SdfLayerHandle layer = ownerPtr->GetLayer();
95 if (layer->_ValidateAuthoring()) {
96 const SdfValueTypeName typeInSchema =
97 layer->GetSchema().FindType(typeName.GetAsToken().GetString());
98 if (!typeInSchema) {
99 TF_CODING_ERROR(
100 "Cannot create attribute spec <%s> with type '%s' not "
101 "supported by schema",
102 attrPath.GetText(), typeName.GetAsToken().GetText());
103 return result;
104 }
105 }
106
107 SdfChangeBlock block;
108
109 // AttributeSpecs are considered initially to have only required fields
110 // only if they are not custom.
111 const bool hasOnlyRequiredFields = (!custom);
112
113 if (!Sdf_ChildrenUtils<Sdf_AttributeChildPolicy>::CreateSpec(
114 layer, attrPath, SdfSpecTypeAttribute, hasOnlyRequiredFields)) {
115 return result;
116 }
117
118 result = layer->GetAttributeAtPath(attrPath);
119
120 // Avoid expensive dormancy checks
121 SdfAttributeSpec *resultPtr = get_pointer(result);
122 if (TF_VERIFY(resultPtr)) {
123 resultPtr->SetField(SdfFieldKeys->Custom, custom);
124 resultPtr->SetField(SdfFieldKeys->TypeName, typeName.GetAsToken());
125 resultPtr->SetField(SdfFieldKeys->Variability, variability);
126 }
127
128 return result;
129 }
130
131 //
132 // Connections
133 //
134
135 SdfConnectionsProxy
GetConnectionPathList() const136 SdfAttributeSpec::GetConnectionPathList() const
137 {
138 return SdfGetPathEditorProxy(
139 SdfCreateHandle(this), SdfFieldKeys->ConnectionPaths);
140 }
141
142 bool
HasConnectionPaths() const143 SdfAttributeSpec::HasConnectionPaths() const
144 {
145 return GetConnectionPathList().HasKeys();
146 }
147
148 void
ClearConnectionPaths()149 SdfAttributeSpec::ClearConnectionPaths()
150 {
151 GetConnectionPathList().ClearEdits();
152 }
153
154 //
155 // Metadata, Attribute Value API, and Spec Properties
156 // (methods built on generic SdfSpec accessor macros)
157 //
158
159 // Initialize accessor helper macros to associate with this class and optimize
160 // out the access predicate
161 #define SDF_ACCESSOR_CLASS SdfAttributeSpec
162 #define SDF_ACCESSOR_READ_PREDICATE(key_) SDF_NO_PREDICATE
163 #define SDF_ACCESSOR_WRITE_PREDICATE(key_) SDF_NO_PREDICATE
164
165 // Attribute Value API
166
167 SDF_DEFINE_GET_SET_HAS_CLEAR(AllowedTokens, SdfFieldKeys->AllowedTokens, VtTokenArray)
168
169 SDF_DEFINE_GET_SET_HAS_CLEAR(ColorSpace, SdfFieldKeys->ColorSpace, TfToken)
170
171 TfEnum
GetDisplayUnit() const172 SdfAttributeSpec::GetDisplayUnit() const
173 {
174 // The difference between this and the macro version is that the
175 // macro calls _GetValueWithDefault(). That checks if the value
176 // is empty and, if so, returns the default value from the schema.
177 // But we want to return a default displayUnit that's based on
178 // the role.
179 TfEnum displayUnit;
180 if (HasField(SdfFieldKeys->DisplayUnit, &displayUnit)) {
181 return displayUnit;
182 }
183
184 return GetTypeName().GetDefaultUnit();
185 }
186
187 TfToken
GetRoleName() const188 SdfAttributeSpec::GetRoleName() const
189 {
190 return GetTypeName().GetRole();
191 }
192
193 SDF_DEFINE_SET(DisplayUnit, SdfFieldKeys->DisplayUnit, const TfEnum&)
194 SDF_DEFINE_HAS(DisplayUnit, SdfFieldKeys->DisplayUnit)
195 SDF_DEFINE_CLEAR(DisplayUnit, SdfFieldKeys->DisplayUnit)
196
197 // Defined in primSpec.cpp.
198 bool
199 Sdf_UncheckedCreatePrimInLayer(SdfLayer *layer, SdfPath const &primPath);
200
201 bool
SdfJustCreatePrimAttributeInLayer(const SdfLayerHandle & layer,const SdfPath & attrPath,const SdfValueTypeName & typeName,SdfVariability variability,bool isCustom)202 SdfJustCreatePrimAttributeInLayer(
203 const SdfLayerHandle &layer,
204 const SdfPath &attrPath,
205 const SdfValueTypeName &typeName,
206 SdfVariability variability,
207 bool isCustom)
208 {
209 if (!attrPath.IsPrimPropertyPath()) {
210 TF_CODING_ERROR("Cannot create prim attribute at path '%s' because "
211 "it is not a prim property path",
212 attrPath.GetText());
213 return false;
214 }
215
216 SdfLayer *layerPtr = get_pointer(layer);
217
218 SdfChangeBlock block;
219
220 if (!Sdf_UncheckedCreatePrimInLayer(layerPtr, attrPath.GetParentPath())) {
221 return false;
222 }
223
224 if (!Sdf_ChildrenUtils<Sdf_AttributeChildPolicy>::CreateSpec(
225 layer, attrPath, SdfSpecTypeAttribute,
226 /*hasOnlyRequiredFields=*/!isCustom)) {
227 TF_RUNTIME_ERROR("Failed to create attribute at path '%s' in "
228 "layer @%s@", attrPath.GetText(),
229 layerPtr->GetIdentifier().c_str());
230 return false;
231 }
232
233 layerPtr->SetField(attrPath, SdfFieldKeys->Custom, isCustom);
234 layerPtr->SetField(attrPath, SdfFieldKeys->TypeName, typeName.GetAsToken());
235 layerPtr->SetField(attrPath, SdfFieldKeys->Variability, variability);
236
237 return true;
238 }
239
240 PXR_NAMESPACE_CLOSE_SCOPE
241