Loading...
Searching...
No Matches
listEditor.h
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#ifndef PXR_USD_SDF_LIST_EDITOR_H
25#define PXR_USD_SDF_LIST_EDITOR_H
26
27#include "pxr/pxr.h"
28#include "pxr/base/tf/token.h"
29#include "pxr/usd/sdf/allowed.h"
31#include "pxr/usd/sdf/listOp.h"
32#include "pxr/usd/sdf/path.h"
33#include "pxr/usd/sdf/schema.h"
34#include "pxr/usd/sdf/spec.h"
35
36#include <functional>
37#include <optional>
38
39PXR_NAMESPACE_OPEN_SCOPE
40
41SDF_DECLARE_HANDLES(SdfLayer);
42SDF_DECLARE_HANDLES(SdfSpec);
43
49template <class TypePolicy>
50class Sdf_ListEditor
51{
52 Sdf_ListEditor(const Sdf_ListEditor&) = delete;
53 Sdf_ListEditor& operator=(const Sdf_ListEditor&) = delete;
54private:
55 typedef Sdf_ListEditor<TypePolicy> This;
56
57public:
58 typedef typename TypePolicy::value_type value_type;
59 typedef std::vector<value_type> value_vector_type;
60
61 virtual ~Sdf_ListEditor() = default;
62
63 SdfLayerHandle GetLayer() const
64 {
65 return _owner ? _owner->GetLayer() : SdfLayerHandle();
66 }
67
68 SdfPath GetPath() const
69 {
70 return _owner ? _owner->GetPath() : SdfPath();
71 }
72
73 bool IsValid() const
74 {
75 return !IsExpired();
76 }
77
78 bool IsExpired() const
79 {
80 return !_owner;
81 }
82
83 bool HasKeys() const
84 {
85 if (IsExplicit()) {
86 return true;
87 }
88 else if (IsOrderedOnly()) {
89 return !_GetOperations(SdfListOpTypeOrdered).empty();
90 }
91 else {
92 return (!_GetOperations(SdfListOpTypeAdded).empty() ||
93 !_GetOperations(SdfListOpTypePrepended).empty() ||
94 !_GetOperations(SdfListOpTypeAppended).empty() ||
95 !_GetOperations(SdfListOpTypeDeleted).empty() ||
96 !_GetOperations(SdfListOpTypeOrdered).empty());
97 }
98 }
99
100 virtual bool IsExplicit() const = 0;
101 virtual bool IsOrderedOnly() const = 0;
102
103 virtual SdfAllowed PermissionToEdit(SdfListOpType op) const
104 {
105 if (!_owner) {
106 return SdfAllowed("List editor is expired");
107 }
108
109 if (!_owner->PermissionToEdit()) {
110 return SdfAllowed("Permission denied");
111 }
112
113 return true;
114 }
115
116 virtual bool CopyEdits(const Sdf_ListEditor& rhs) = 0;
117 virtual bool ClearEdits() = 0;
118 virtual bool ClearEditsAndMakeExplicit() = 0;
119
120 typedef std::function<
121 std::optional<value_type>(const value_type&)
122 >
123 ModifyCallback;
124
131 virtual void ModifyItemEdits(const ModifyCallback& cb) = 0;
132
133 typedef std::function<
134 std::optional<value_type>(SdfListOpType, const value_type&)
135 >
136 ApplyCallback;
137
145 virtual void ApplyEditsToList(
146 value_vector_type* vec,
147 const ApplyCallback& cb = ApplyCallback()) = 0;
148
150 size_t GetSize(SdfListOpType op) const
151 {
152 return _GetOperations(op).size();
153 }
154
156 value_type Get(SdfListOpType op, size_t i) const
157 {
158 return _GetOperations(op)[i];
159 }
160
162 value_vector_type GetVector(SdfListOpType op) const
163 {
164 return _GetOperations(op);
165 }
166
169 size_t Count(SdfListOpType op, const value_type& val) const
170 {
171 const value_vector_type& ops = _GetOperations(op);
172 return std::count(ops.begin(), ops.end(), _typePolicy.Canonicalize(val));
173 }
174
177 size_t Find(SdfListOpType op, const value_type& val) const
178 {
179 const value_vector_type& vec = _GetOperations(op);
180 typename value_vector_type::const_iterator findIt =
181 std::find(vec.begin(), vec.end(), _typePolicy.Canonicalize(val));
182 if (findIt != vec.end()) {
183 return std::distance(vec.begin(), findIt);
184 }
185
186 return size_t(-1);
187 }
188
191 virtual bool ReplaceEdits(
192 SdfListOpType op, size_t index, size_t n,
193 const value_vector_type& elems) = 0;
194
196 virtual void ApplyList(SdfListOpType op, const Sdf_ListEditor& rhs) = 0;
197
198protected:
199 Sdf_ListEditor()
200 {
201 }
202
203 Sdf_ListEditor(const SdfSpecHandle& owner, const TfToken& field,
204 const TypePolicy& typePolicy)
205 : _owner(owner),
206 _field(field),
207 _typePolicy(typePolicy)
208 {
209 }
210
211 const SdfSpecHandle& _GetOwner() const
212 {
213 return _owner;
214 }
215
216 const TfToken& _GetField() const
217 {
218 return _field;
219 }
220
221 const TypePolicy& _GetTypePolicy() const
222 {
223 return _typePolicy;
224 }
225
226 virtual bool _ValidateEdit(SdfListOpType op,
227 const value_vector_type& oldValues,
228 const value_vector_type& newValues) const
229 {
230 // Disallow duplicate items from being stored in the new list
231 // editor values. This is O(n^2), but we expect the number of elements
232 // stored to be small enough that this won't matter.
233 //
234 // XXX:
235 // We assume that duplicate data items are never allowed to be
236 // authored. For full generality, this information ought to come from
237 // the layer schema.
238
239 // We also assume that the `oldValues` are already valid and do not
240 // contain duplicates. With this assumption, we can accelerate the
241 // common case of appending new items at the end and skip over a common
242 // prefix of oldValues and newValues. Then we can only check for dupes
243 // in the tail of newValues.
244
245 typename value_vector_type::const_iterator
246 oldValuesTail = oldValues.begin(),
247 newValuesTail = newValues.begin();
248 auto oldEnd = oldValues.end(), newEnd = newValues.end();
249 while (oldValuesTail != oldEnd && newValuesTail != newEnd &&
250 *oldValuesTail == *newValuesTail) {
251 ++oldValuesTail, ++newValuesTail;
252 }
253
254 for (auto i = newValuesTail; i != newEnd; ++i) {
255 // Have to check unmatched new items for dupes.
256 for (auto j = newValues.begin(); j != i; ++j) {
257 if (*i == *j) {
258 TF_CODING_ERROR("Duplicate item '%s' not allowed for "
259 "field '%s' on <%s>",
260 TfStringify(*i).c_str(),
261 _field.GetText(),
262 this->GetPath().GetText());
263 return false;
264 }
265 }
266 }
267
268 // Ensure that all new values are valid for this field.
269 const SdfSchema::FieldDefinition* fieldDef =
270 _owner->GetSchema().GetFieldDefinition(_field);
271 if (!fieldDef) {
272 TF_CODING_ERROR("No field definition for field '%s'",
273 _field.GetText());
274 }
275 else {
276 for (auto i = newValuesTail; i != newEnd; ++i) {
277 if (SdfAllowed isValid = fieldDef->IsValidListValue(*i)) { }
278 else {
279 TF_CODING_ERROR("%s", isValid.GetWhyNot().c_str());
280 return false;
281 }
282 }
283 }
284
285 return true;
286 }
287
288 virtual void _OnEdit(SdfListOpType op,
289 const value_vector_type& oldValues,
290 const value_vector_type& newValues) const
291 {
292 }
293
294 virtual const value_vector_type& _GetOperations(SdfListOpType op) const = 0;
295
296private:
297 SdfSpecHandle _owner;
298 TfToken _field;
299 TypePolicy _typePolicy;
300
301};
302
303template <class TypePolicy>
304std::ostream&
305operator<<(std::ostream& s, const Sdf_ListEditor<TypePolicy>& x)
306{
307 struct Util {
308 typedef typename Sdf_ListEditor<TypePolicy>::value_vector_type
309 value_vector_type;
310
311 static void _Write(std::ostream& s, const value_vector_type& v)
312 {
313 s << '[';
314 for (size_t i = 0, n = v.size(); i < n; ++i) {
315 if (i != 0) {
316 s << ", ";
317 }
318 s << v[i];
319 }
320 s << ']';
321 }
322 };
323
324 if (!x.IsValid()) {
325 return s;
326 }
327 else if (x.IsExplicit()) {
328 Util::_Write(s, x.GetVector(SdfListOpTypeExplicit));
329 return s;
330 }
331 else {
332 s << "{ ";
333 if (!x.IsOrderedOnly()) {
334 s << "'added': ";
335 Util::_Write(s, x.GetVector(SdfListOpTypeAdded));
336 s << "'prepended': ";
337 Util::_Write(s, x.GetVector(SdfListOpTypePrepended));
338 s << "'appended': ";
339 Util::_Write(s, x.GetVector(SdfListOpTypeAppended));
340 s << ", 'deleted': ";
341 Util::_Write(s, x.GetVector(SdfListOpTypeDeleted));
342 s << ", ";
343 }
344 s << "'ordered': ";
345 Util::_Write(s, x.GetVector(SdfListOpTypeOrdered));
346 return s << " }";
347 }
348}
349
350PXR_NAMESPACE_CLOSE_SCOPE
351
352#endif // PXR_USD_SDF_LIST_EDITOR_H
Indicates if an operation is allowed and, if not, why not.
Definition: allowed.h:46
A scene description container that can combine with other such containers to form simple component as...
Definition: layer.h:100
A path value used to locate objects in layers or scenegraphs.
Definition: path.h:291
Class defining various attributes for a field.
Definition: schema.h:73
Base class for all Sdf spec classes.
Definition: spec.h:50
Token for efficient comparison, assignment, and hashing of known strings.
Definition: token.h:88
GF_API std::ostream & operator<<(std::ostream &, const GfBBox3d &)
Output a GfBBox3d using the format [(range) matrix zeroArea].
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
Definition: diagnostic.h:85
std::string TfStringify(const T &v)
Convert an arbitrary type into a string.
Definition: stringUtils.h:572
TfToken class for efficient string referencing and hashing, plus conversions to and from stl string c...