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