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