All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
listOpListEditor.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 SDF_LIST_OP_LIST_EDITOR_H
25 #define SDF_LIST_OP_LIST_EDITOR_H
26 
27 #include "pxr/pxr.h"
28 #include "pxr/usd/sdf/listEditor.h"
29 #include "pxr/usd/sdf/changeBlock.h"
30 #include "pxr/usd/sdf/spec.h"
31 #include "pxr/usd/sdf/path.h"
32 #include "pxr/usd/sdf/layer.h"
33 #include "pxr/usd/sdf/listOp.h"
34 
35 PXR_NAMESPACE_OPEN_SCOPE
36 
42 template <class TypePolicy>
43 class Sdf_ListOpListEditor
44  : public Sdf_ListEditor<TypePolicy>
45 {
46 private:
47  typedef Sdf_ListOpListEditor<TypePolicy> This;
48  typedef Sdf_ListEditor<TypePolicy> Parent;
49 
50  typedef SdfListOp<typename Parent::value_type> ListOpType;
51 
52 public:
53  typedef typename Parent::value_type value_type;
54  typedef typename Parent::value_vector_type value_vector_type;
55 
56  Sdf_ListOpListEditor(const SdfSpecHandle& owner, const TfToken& listField,
57  const TypePolicy& typePolicy = TypePolicy());
58 
59  virtual ~Sdf_ListOpListEditor() = default;
60 
61  virtual bool IsExplicit() const;
62  virtual bool IsOrderedOnly() const;
63 
64  virtual bool CopyEdits(const Sdf_ListEditor<TypePolicy>& rhs);
65  virtual bool ClearEdits();
66  virtual bool ClearEditsAndMakeExplicit();
67 
68  typedef typename Parent::ModifyCallback ModifyCallback;
69  virtual void ModifyItemEdits(const ModifyCallback& cb);
70 
71  typedef typename Parent::ApplyCallback ApplyCallback;
72  virtual void ApplyEditsToList(
73  value_vector_type* vec, const ApplyCallback& cb);
74 
75  virtual bool ReplaceEdits(
76  SdfListOpType op, size_t index, size_t n, const value_vector_type& elems);
77 
78  virtual void ApplyList(
79  SdfListOpType opType, const Sdf_ListEditor<TypePolicy>& rhs);
80 
81 protected:
82  // Pull in protected functions from base class; this is needed because
83  // these are non-dependent names and the compiler won't look in
84  // dependent base-classes for these.
85  using Parent::_GetField;
86  using Parent::_GetOwner;
87  using Parent::_GetTypePolicy;
88  using Parent::_ValidateEdit;
89 
90  virtual const value_vector_type& _GetOperations(SdfListOpType op) const;
91 
92 private:
93  static
94  boost::optional<value_type>
95  _ModifyCallbackHelper(const ModifyCallback& cb,
96  const TypePolicy& typePolicy,
97  const value_type& v)
98  {
99  boost::optional<value_type> value = cb(v);
100  return value ? typePolicy.Canonicalize(*value) : value;
101  }
102 
103  static bool _ListDiffers(SdfListOpType op,
104  const ListOpType& x, const ListOpType& y)
105  {
106  return x.GetItems(op) != y.GetItems(op);
107  }
108 
109  void _UpdateListOp(const ListOpType& newListOp,
110  const SdfListOpType* updatedListOpType = NULL)
111  {
112  if (!_GetOwner()) {
113  TF_CODING_ERROR("Invalid owner.");
114  return;
115  }
116 
117  if (!_GetOwner()->GetLayer()->PermissionToEdit()) {
118  TF_CODING_ERROR("Layer is not editable.");
119  return;
120  }
121 
122  // Check if any of the list operation vectors have changed and validate
123  // their new contents.
124  std::pair<const SdfListOpType, bool> opTypesAndChanged[] = {
125  { SdfListOpTypeExplicit, false },
126  { SdfListOpTypeAdded, false },
127  { SdfListOpTypeDeleted, false },
128  { SdfListOpTypeOrdered, false },
129  { SdfListOpTypePrepended, false },
130  { SdfListOpTypeAppended, false }
131  };
132  bool anyChanged = false;
133 
134  for (auto& opTypeAndChanged : opTypesAndChanged) {
135  // If the consumer has specified that only a single op type has
136  // changed, ignore all others.
137  if (updatedListOpType &&
138  *updatedListOpType != opTypeAndChanged.first) {
139  continue;
140  }
141 
142  opTypeAndChanged.second =
143  _ListDiffers(opTypeAndChanged.first, newListOp, _listOp);
144  if (opTypeAndChanged.second) {
145  if (!_ValidateEdit(
146  opTypeAndChanged.first,
147  _listOp.GetItems(opTypeAndChanged.first),
148  newListOp.GetItems(opTypeAndChanged.first))) {
149  return;
150  }
151  anyChanged = true;
152  }
153  }
154 
155  if (!anyChanged &&
156  (newListOp.IsExplicit() == _listOp.IsExplicit())) {
157  return;
158  }
159 
160  // Save away the old SdfListOp and set in our new one.
161  SdfChangeBlock block;
162 
163  ListOpType oldListOp = newListOp;
164  _listOp.Swap(oldListOp);
165 
166  if (newListOp.HasKeys()) {
167  _GetOwner()->SetField(_GetField(), VtValue(newListOp));
168  } else {
169  _GetOwner()->ClearField(_GetField());
170  }
171 
172  // For each operation list that changed, call helper function to allow
173  // subclasses to execute additional behavior in response to changes.
174  for (auto& opTypeAndChanged : opTypesAndChanged) {
175  if (opTypeAndChanged.second) {
176  this->_OnEdit(opTypeAndChanged.first,
177  oldListOp.GetItems(opTypeAndChanged.first),
178  newListOp.GetItems(opTypeAndChanged.first));
179  }
180  }
181  }
182 
183 private:
184  ListOpType _listOp;
185 };
186 
188 
189 template <class TP>
190 Sdf_ListOpListEditor<TP>::Sdf_ListOpListEditor(
191  const SdfSpecHandle& owner,
192  const TfToken& listField,
193  const TP& typePolicy)
194  : Parent(owner, listField, typePolicy)
195 {
196  if (owner) {
197  _listOp = owner->GetFieldAs<ListOpType>(_GetField());
198  }
199 }
200 
201 template <class TP>
202 bool
203 Sdf_ListOpListEditor<TP>::IsExplicit() const
204 {
205  return _listOp.IsExplicit();
206 }
207 
208 template <class TP>
209 bool
210 Sdf_ListOpListEditor<TP>::IsOrderedOnly() const
211 {
212  return false;
213 }
214 
215 template <class TP>
216 bool
217 Sdf_ListOpListEditor<TP>::CopyEdits(const Sdf_ListEditor<TP>& rhs)
218 {
219  const This* rhsEdit = dynamic_cast<const This*>(&rhs);
220  if (!rhsEdit) {
221  TF_CODING_ERROR("Could not copy from list editor of different type");
222  return false;
223  }
224 
225  _UpdateListOp(rhsEdit->_listOp);
226  return true;
227 }
228 
229 template <class TP>
230 bool
231 Sdf_ListOpListEditor<TP>::ClearEdits()
232 {
233  ListOpType emptyAndNotExplicit;
234 
235  _UpdateListOp(emptyAndNotExplicit);
236  return true;
237 }
238 
239 template <class TP>
240 bool
241 Sdf_ListOpListEditor<TP>::ClearEditsAndMakeExplicit()
242 {
243  ListOpType emptyAndExplicit;
244  emptyAndExplicit.ClearAndMakeExplicit();
245 
246  _UpdateListOp(emptyAndExplicit);
247  return true;
248 }
249 
250 template <class TP>
251 void
252 Sdf_ListOpListEditor<TP>::ModifyItemEdits(const ModifyCallback& cb)
253 {
254  ListOpType modifiedListOp = _listOp;
255  modifiedListOp.ModifyOperations(
256  [this, &cb](const value_type &t) {
257  return _ModifyCallbackHelper(cb, _GetTypePolicy(), t);
258  });
259 
260  _UpdateListOp(modifiedListOp);
261 }
262 
263 template <class TP>
264 void
265 Sdf_ListOpListEditor<TP>::ApplyEditsToList(
266  value_vector_type* vec, const ApplyCallback& cb)
267 {
268  _listOp.ApplyOperations(vec, cb);
269 }
270 
271 template <class TP>
272 bool
273 Sdf_ListOpListEditor<TP>::ReplaceEdits(
274  SdfListOpType opType, size_t index, size_t n,
275  const value_vector_type& newItems)
276 {
277  ListOpType editedListOp = _listOp;
278  if (!editedListOp.ReplaceOperations(
279  opType, index, n,
280  _GetTypePolicy().Canonicalize(newItems))) {
281  return false;
282  }
283 
284  _UpdateListOp(editedListOp, &opType);
285  return true;
286 }
287 
288 template <class TP>
289 void
290 Sdf_ListOpListEditor<TP>::ApplyList(
291  SdfListOpType opType, const Sdf_ListEditor<TP>& rhs)
292 
293 {
294  const This* rhsEdit = dynamic_cast<const This*>(&rhs);
295  if (!rhsEdit) {
296  TF_CODING_ERROR("Cannot apply from list editor of different type");
297  return;
298  }
299 
300  ListOpType composedListOp = _listOp;
301  composedListOp.ComposeOperations(rhsEdit->_listOp, opType);
302 
303  _UpdateListOp(composedListOp, &opType);
304 }
305 
306 template <class TP>
307 const typename Sdf_ListOpListEditor<TP>::value_vector_type&
308 Sdf_ListOpListEditor<TP>::_GetOperations(SdfListOpType op) const
309 {
310  return _listOp.GetItems(op);
311 }
312 
313 PXR_NAMESPACE_CLOSE_SCOPE
314 
315 #endif // SDF_LIST_OP_LIST_EDITOR_H
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
Definition: diagnostic.h:87
Token for efficient comparison, assignment, and hashing of known strings.
Definition: token.h:89
DANGER DANGER DANGER
Definition: changeBlock.h:72
Value type representing a list-edit operation.
Definition: listOp.h:75
Provides a container which may hold any type, and provides introspection and iteration over array typ...
Definition: value.h:182