HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
listEditor.h
Go to the documentation of this file.
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 <hboost/noncopyable.hpp>
37 #include <hboost/optional.hpp>
38 
39 #include <functional>
40 
42 
45 
46 /// \class Sdf_ListEditor
47 ///
48 /// Base class for list editor implementations in which list editing operations
49 /// are stored in data field(s) associated with an owning spec.
50 ///
51 template <class TypePolicy>
53  : public hboost::noncopyable
54 {
55 private:
57 
58 public:
60  typedef std::vector<value_type> value_vector_type;
61 
62  SdfLayerHandle GetLayer() const
63  {
64  return _owner ? _owner->GetLayer() : SdfLayerHandle();
65  }
66 
67  SdfPath GetPath() const
68  {
69  return _owner ? _owner->GetPath() : SdfPath();
70  }
71 
72  bool IsValid() const
73  {
74  return !IsExpired();
75  }
76 
77  bool IsExpired() const
78  {
79  return !_owner;
80  }
81 
82  bool HasKeys() const
83  {
84  if (IsExplicit()) {
85  return true;
86  }
87  else if (IsOrderedOnly()) {
88  return !_GetOperations(SdfListOpTypeOrdered).empty();
89  }
90  else {
91  return (!_GetOperations(SdfListOpTypeAdded).empty() ||
96  }
97  }
98 
99  virtual bool IsExplicit() const = 0;
100  virtual bool IsOrderedOnly() const = 0;
101 
103  {
104  if (!_owner) {
105  return SdfAllowed("List editor is expired");
106  }
107 
108  if (!_owner->PermissionToEdit()) {
109  return SdfAllowed("Permission denied");
110  }
111 
112  return true;
113  }
114 
115  virtual bool CopyEdits(const Sdf_ListEditor& rhs) = 0;
116  virtual bool ClearEdits() = 0;
117  virtual bool ClearEditsAndMakeExplicit() = 0;
118 
119  typedef std::function<
120  hboost::optional<value_type>(const value_type&)
121  >
123 
124  /// Modifies the operations stored in all operation lists.
125  /// \p callback is called for every key. If the returned key is
126  /// invalid then the key is removed, otherwise it's replaced with the
127  /// returned key.
128  virtual void ModifyItemEdits(const ModifyCallback& cb) = 0;
129 
130  typedef std::function<
131  hboost::optional<value_type>(SdfListOpType, const value_type&)
132  >
134 
135  /// Apply the list operations represented by this interface to the given
136  /// vector of values \p vec. If \p callback is valid then it's called
137  /// for every key in the editor before applying it to \p vec. If the
138  /// returned key is empty then the key will not be applied. Otherwise
139  /// the returned key is applied, allowing callbacks to perform key
140  /// translation. Note that this means list editors can't meaningfully
141  /// hold the empty key.
142  virtual void ApplyEditsToList(
143  value_vector_type* vec,
144  const ApplyCallback& cb = ApplyCallback()) = 0;
145 
146  /// Returns the number of elements in the specified list of operations.
147  size_t GetSize(SdfListOpType op) const
148  {
149  return _GetOperations(op).size();
150  }
151 
152  /// Returns the \p i'th value in the specified list of operations.
153  value_type Get(SdfListOpType op, size_t i) const
154  {
155  return _GetOperations(op)[i];
156  }
157 
158  /// Returns the specified list of operations.
160  {
161  return _GetOperations(op);
162  }
163 
164  /// Returns the number of occurrences of \p val in the specified list of
165  /// operations.
166  size_t Count(SdfListOpType op, const value_type& val) const
167  {
168  const value_vector_type& ops = _GetOperations(op);
169  return std::count(ops.begin(), ops.end(), _typePolicy.Canonicalize(val));
170  }
171 
172  /// Returns the index of \p val in the specified list of operations, -1
173  /// if \p val is not found.
174  size_t Find(SdfListOpType op, const value_type& val) const
175  {
176  const value_vector_type& vec = _GetOperations(op);
177  typename value_vector_type::const_iterator findIt =
178  std::find(vec.begin(), vec.end(), _typePolicy.Canonicalize(val));
179  if (findIt != vec.end()) {
180  return std::distance(vec.begin(), findIt);
181  }
182 
183  return size_t(-1);
184  }
185 
186  /// Replaces the operations in the specified list of operations in range
187  /// [index, index + n) with the given \p elems.
188  virtual bool ReplaceEdits(
189  SdfListOpType op, size_t index, size_t n,
190  const value_vector_type& elems) = 0;
191 
192  /// Applies a \p rhs opinions about a given operation list to this one.
193  virtual void ApplyList(SdfListOpType op, const Sdf_ListEditor& rhs) = 0;
194 
195 protected:
197  {
198  }
199 
200  Sdf_ListEditor(const SdfSpecHandle& owner, const TfToken& field,
201  const TypePolicy& typePolicy)
202  : _owner(owner),
203  _field(field),
204  _typePolicy(typePolicy)
205  {
206  }
207 
208  virtual ~Sdf_ListEditor() = default;
209 
210  const SdfSpecHandle& _GetOwner() const
211  {
212  return _owner;
213  }
214 
215  const TfToken& _GetField() const
216  {
217  return _field;
218  }
219 
220  const TypePolicy& _GetTypePolicy() const
221  {
222  return _typePolicy;
223  }
224 
225  virtual bool _ValidateEdit(SdfListOpType op,
226  const value_vector_type& oldValues,
227  const value_vector_type& newValues) const
228  {
229  // Disallow duplicate items from being stored in the new list
230  // editor values. This is O(n^2), but we expect the number of elements
231  // stored to be small enough that this won't matter.
232  //
233  // XXX:
234  // We assume that duplicate data items are never allowed to be
235  // authored. For full generality, this information ought to come from
236  // the layer schema.
237 
238  // We also assume that the `oldValues` are already valid and do not
239  // contain duplicates. With this assumption, we can accelerate the
240  // common case of appending new items at the end and skip over a common
241  // prefix of oldValues and newValues. Then we can only check for dupes
242  // in the tail of newValues.
243 
244  typename value_vector_type::const_iterator
245  oldValuesTail = oldValues.begin(),
246  newValuesTail = newValues.begin();
247  auto oldEnd = oldValues.end(), newEnd = newValues.end();
248  while (oldValuesTail != oldEnd && newValuesTail != newEnd &&
249  *oldValuesTail == *newValuesTail) {
250  ++oldValuesTail, ++newValuesTail;
251  }
252 
253  for (auto i = newValuesTail; i != newEnd; ++i) {
254  // Have to check unmatched new items for dupes.
255  for (auto j = newValues.begin(); j != i; ++j) {
256  if (*i == *j) {
257  TF_CODING_ERROR("Duplicate item '%s' not allowed for "
258  "field '%s' on <%s>",
259  TfStringify(*i).c_str(),
260  _field.GetText(),
261  this->GetPath().GetText());
262  return false;
263  }
264  }
265  }
266 
267  // Ensure that all new values are valid for this field.
268  const SdfSchema::FieldDefinition* fieldDef =
269  _owner->GetSchema().GetFieldDefinition(_field);
270  if (!fieldDef) {
271  TF_CODING_ERROR("No field definition for field '%s'",
272  _field.GetText());
273  }
274  else {
275  for (auto i = newValuesTail; i != newEnd; ++i) {
276  if (SdfAllowed isValid = fieldDef->IsValidListValue(*i)) { }
277  else {
278  TF_CODING_ERROR("%s", isValid.GetWhyNot().c_str());
279  return false;
280  }
281  }
282  }
283 
284  return true;
285  }
286 
287  virtual void _OnEdit(SdfListOpType op,
288  const value_vector_type& oldValues,
289  const value_vector_type& newValues) const
290  {
291  }
292 
293  virtual const value_vector_type& _GetOperations(SdfListOpType op) const = 0;
294 
295 private:
296  SdfSpecHandle _owner;
297  TfToken _field;
298  TypePolicy _typePolicy;
299 
300 };
301 
302 template <class TypePolicy>
303 std::ostream&
304 operator<<(std::ostream& s, const Sdf_ListEditor<TypePolicy>& x)
305 {
306  struct Util {
308  value_vector_type;
309 
310  static void _Write(std::ostream& s, const value_vector_type& v)
311  {
312  s << '[';
313  for (size_t i = 0, n = v.size(); i < n; ++i) {
314  if (i != 0) {
315  s << ", ";
316  }
317  s << v[i];
318  }
319  s << ']';
320  }
321  };
322 
323  if (!x.IsValid()) {
324  return s;
325  }
326  else if (x.IsExplicit()) {
327  Util::_Write(s, x.GetVector(SdfListOpTypeExplicit));
328  return s;
329  }
330  else {
331  s << "{ ";
332  if (!x.IsOrderedOnly()) {
333  s << "'added': ";
334  Util::_Write(s, x.GetVector(SdfListOpTypeAdded));
335  s << "'prepended': ";
336  Util::_Write(s, x.GetVector(SdfListOpTypePrepended));
337  s << "'appended': ";
338  Util::_Write(s, x.GetVector(SdfListOpTypeAppended));
339  s << ", 'deleted': ";
340  Util::_Write(s, x.GetVector(SdfListOpTypeDeleted));
341  s << ", ";
342  }
343  s << "'ordered': ";
344  Util::_Write(s, x.GetVector(SdfListOpTypeOrdered));
345  return s << " }";
346  }
347 }
348 
350 
351 #endif // PXR_USD_SDF_LIST_EDITOR_H
virtual const value_vector_type & _GetOperations(SdfListOpType op) const =0
SDF_API const char * GetText() const
Definition: layer.h:96
size_t Find(SdfListOpType op, const value_type &val) const
Definition: listEditor.h:174
virtual bool IsOrderedOnly() const =0
bool HasKeys() const
Definition: listEditor.h:82
#define TF_CODING_ERROR
virtual void _OnEdit(SdfListOpType op, const value_vector_type &oldValues, const value_vector_type &newValues) const
Definition: listEditor.h:287
Definition: spec.h:51
virtual bool ClearEdits()=0
uint64 value_type
Definition: GA_PrimCompat.h:29
TypePolicy::value_type value_type
Definition: listEditor.h:59
const TypePolicy & _GetTypePolicy() const
Definition: listEditor.h:220
value_type Get(SdfListOpType op, size_t i) const
Returns the i'th value in the specified list of operations.
Definition: listEditor.h:153
GLint GLenum GLint x
Definition: glcorearb.h:408
virtual SdfAllowed PermissionToEdit(SdfListOpType op) const
Definition: listEditor.h:102
const SdfSpecHandle & _GetOwner() const
Definition: listEditor.h:210
Definition: token.h:87
bool IsValid() const
Definition: listEditor.h:72
virtual bool ReplaceEdits(SdfListOpType op, size_t index, size_t n, const value_vector_type &elems)=0
virtual bool IsExplicit() const =0
SdfListOpType
Definition: listOp.h:47
GLsizei GLsizei GLfloat distance
Definition: glew.h:13923
FMT_CONSTEXPR bool find(Ptr first, Ptr last, T value, Ptr &out)
Definition: format.h:2929
const GLdouble * v
Definition: glcorearb.h:836
Sdf_ListEditor(const SdfSpecHandle &owner, const TfToken &field, const TypePolicy &typePolicy)
Definition: listEditor.h:200
SdfLayerHandle GetLayer() const
Definition: listEditor.h:62
virtual void ModifyItemEdits(const ModifyCallback &cb)=0
virtual void ApplyList(SdfListOpType op, const Sdf_ListEditor &rhs)=0
Applies a rhs opinions about a given operation list to this one.
const TfToken & _GetField() const
Definition: listEditor.h:215
GLint GLsizei count
Definition: glcorearb.h:404
Definition: path.h:288
std::vector< value_type > value_vector_type
Definition: listEditor.h:60
char const * GetText() const
Definition: token.h:196
std::function< hboost::optional< value_type >const value_type &) > ModifyCallback
Definition: listEditor.h:122
GLdouble n
Definition: glcorearb.h:2007
GLuint GLfloat * val
Definition: glcorearb.h:1607
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1375
size_t Count(SdfListOpType op, const value_type &val) const
Definition: listEditor.h:166
GLuint index
Definition: glcorearb.h:785
SdfAllowed IsValidListValue(const T &value) const
Definition: schema.h:102
virtual bool ClearEditsAndMakeExplicit()=0
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:91
bool IsExpired() const
Definition: listEditor.h:77
virtual ~Sdf_ListEditor()=default
PXR_NAMESPACE_OPEN_SCOPE SDF_DECLARE_HANDLES(SdfLayer)
std::enable_if<!std::is_enum< T >::value, std::string >::type TfStringify(const T &v)
Definition: stringUtils.h:527
SdfPath GetPath() const
Definition: listEditor.h:67
GLdouble s
Definition: glew.h:1395
virtual void ApplyEditsToList(value_vector_type *vec, const ApplyCallback &cb=ApplyCallback())=0
size_t GetSize(SdfListOpType op) const
Returns the number of elements in the specified list of operations.
Definition: listEditor.h:147
std::function< hboost::optional< value_type >SdfListOpType, const value_type &) > ApplyCallback
Definition: listEditor.h:133
value_vector_type GetVector(SdfListOpType op) const
Returns the specified list of operations.
Definition: listEditor.h:159
virtual bool _ValidateEdit(SdfListOpType op, const value_vector_type &oldValues, const value_vector_type &newValues) const
Definition: listEditor.h:225
virtual bool CopyEdits(const Sdf_ListEditor &rhs)=0