All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
vectorListEditor.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_VECTOR_LIST_EDITOR_H
25 #define SDF_VECTOR_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/listOp.h"
31 
32 #include "pxr/base/tf/ostreamMethods.h"
33 #include <vector>
34 
35 PXR_NAMESPACE_OPEN_SCOPE
36 
37 // Various adapter classes used by Sdf_VectorListEditor to allow for
38 // conversions between the publicly exposed value type and the underlying
39 // field data type.
40 template <class To, class From>
41 struct Sdf_VectorFieldAdapter;
42 
43 template <class T>
44 struct Sdf_VectorFieldAdapter<T, T>
45 {
46  static const std::vector<T>& Convert(const std::vector<T>& from)
47  {
48  return from;
49  }
50 };
51 
52 template <>
53 struct Sdf_VectorFieldAdapter<TfToken, std::string>
54 {
55  static std::vector<TfToken> Convert(const std::vector<std::string>& from)
56  {
57  return TfToTokenVector(from);
58  }
59 };
60 
61 template <>
62 struct Sdf_VectorFieldAdapter<std::string, TfToken>
63 {
64  static std::vector<std::string> Convert(const std::vector<TfToken>& from)
65  {
66  return TfToStringVector(from);
67  }
68 };
69 
80 template <class TypePolicy,
81  class FieldStorageType = typename TypePolicy::value_type>
82 class Sdf_VectorListEditor
83  : public Sdf_ListEditor<TypePolicy>
84 {
85 private:
86  typedef Sdf_VectorListEditor<
87  TypePolicy, FieldStorageType> This;
88  typedef Sdf_ListEditor<TypePolicy> Parent;
89 
90 public:
91  typedef typename Parent::value_type value_type;
92  typedef typename Parent::value_vector_type value_vector_type;
93 
94  virtual ~Sdf_VectorListEditor() = default;
95 
96  Sdf_VectorListEditor(const SdfSpecHandle& owner,
97  const TfToken& field, SdfListOpType op,
98  const TypePolicy& typePolicy = TypePolicy());
99 
100  virtual bool IsExplicit() const;
101  virtual bool IsOrderedOnly() const;
102 
103  virtual bool CopyEdits(const Sdf_ListEditor<TypePolicy>& rhs);
104  virtual bool ClearEdits();
105  virtual bool ClearEditsAndMakeExplicit();
106 
107  typedef typename Parent::ModifyCallback ModifyCallback;
108  virtual void ModifyItemEdits(const ModifyCallback& cb);
109 
110  typedef typename Parent::ApplyCallback ApplyCallback;
111  virtual void ApplyEditsToList(
112  value_vector_type* vec, const ApplyCallback& cb);
113 
114  virtual bool ReplaceEdits(
115  SdfListOpType op, size_t index, size_t n, const value_vector_type& elems);
116 
117  virtual void ApplyList(
118  SdfListOpType op, const Sdf_ListEditor<TypePolicy>& rhs);
119 
120 protected:
121  using Parent::_GetField;
122  using Parent::_GetOwner;
123  using Parent::_GetTypePolicy;
124  using Parent::_ValidateEdit;
125 
126  virtual const value_vector_type& _GetOperations(SdfListOpType op) const;
127 
128 private:
129  static
130  boost::optional<value_type>
131  _ModifyCallbackHelper(const ModifyCallback& cb,
132  const TypePolicy& typePolicy,
133  const value_type& v)
134  {
135  boost::optional<value_type> value = cb(v);
136  return value ? typePolicy.Canonicalize(*value) : value;
137  }
138 
139  void _UpdateFieldData(const value_vector_type& newData)
140  {
141  if (!_GetOwner()) {
142  TF_CODING_ERROR("Invalid owner.");
143  return;
144  }
145 
146  if (!_GetOwner()->GetLayer()->PermissionToEdit()) {
147  TF_CODING_ERROR("Layer is not editable.");
148  return;
149  }
150 
151  if (newData == _data || !_ValidateEdit(_op, _data, newData)) {
152  return;
153  }
154 
155  SdfChangeBlock changeBlock;
156 
157  value_vector_type oldData = newData;
158  _data.swap(oldData);
159 
160  if (newData.empty()) {
161  _GetOwner()->ClearField(_GetField());
162  }
163  else {
164  typedef Sdf_VectorFieldAdapter<FieldStorageType, value_type>
165  ToFieldType;
166  const std::vector<FieldStorageType> newFieldData =
167  ToFieldType::Convert(newData);
168  _GetOwner()->SetField(_GetField(), newFieldData);
169  }
170 
171  this->_OnEdit(_op, oldData, newData);
172  }
173 
174 private:
175  TfToken _field;
176  SdfListOpType _op;
177  value_vector_type _data;
178 };
179 
181 
182 template <class TP, class FST>
183 Sdf_VectorListEditor<TP, FST>::Sdf_VectorListEditor(
184  const SdfSpecHandle& owner,
185  const TfToken& field, SdfListOpType op,
186  const TP& typePolicy)
187  : Parent(owner, field, typePolicy),
188  _op(op)
189 {
190  if (owner) {
191  typedef std::vector<FST> FieldVectorType;
192  typedef Sdf_VectorFieldAdapter<value_type, FST> ToValueType;
193 
194  _data = ToValueType::Convert(owner->GetFieldAs<FieldVectorType>(field));
195  }
196 }
197 
198 template <class TP, class FST>
199 bool
200 Sdf_VectorListEditor<TP, FST>::IsExplicit() const
201 {
202  return _op == SdfListOpTypeExplicit;
203 }
204 
205 template <class TP, class FST>
206 bool
207 Sdf_VectorListEditor<TP, FST>::IsOrderedOnly() const
208 {
209  return _op == SdfListOpTypeOrdered;
210 }
211 
212 template <class TP, class FST>
213 bool
214 Sdf_VectorListEditor<TP, FST>::CopyEdits(const Sdf_ListEditor<TP>& rhs)
215 {
216  const This* rhsEdit = dynamic_cast<const This*>(&rhs);
217  if (!rhsEdit) {
218  TF_CODING_ERROR("Cannot copy from list editor of different type");
219  return false;
220  }
221 
222  if (_op != rhsEdit->_op) {
223  TF_CODING_ERROR("Cannot copy from list editor in different mode");
224  return false;
225  }
226 
227  _UpdateFieldData(rhsEdit->_data);
228  return true;
229 }
230 
231 template <class TP, class FST>
232 bool
233 Sdf_VectorListEditor<TP, FST>::ClearEdits()
234 {
235  // Per specification of ClearEdits, we need to return false if we're
236  // not able to switch to non-explicit mode. This list editor doesn't
237  // allow any mode switching at all, so we need to return false if we're
238  // explicit.
239  if (_op == SdfListOpTypeExplicit) {
240  return false;
241  }
242 
243  _UpdateFieldData(value_vector_type());
244  return true;
245 }
246 
247 template <class TP, class FST>
248 bool
249 Sdf_VectorListEditor<TP, FST>::ClearEditsAndMakeExplicit()
250 {
251  // Per specification of ClearEditsAndMakeExplicit, we need to return
252  // false if we're not able to switch to explicit mode. This list editor
253  // doesn't allow any mode switching at all, so we need to return false
254  // if we're not already explicit.
255  if (_op != SdfListOpTypeExplicit) {
256  return false;
257  }
258 
259  _UpdateFieldData(value_vector_type());
260  return true;
261 }
262 
263 template <class TP, class FST>
264 void
265 Sdf_VectorListEditor<TP, FST>::ModifyItemEdits(const ModifyCallback& cb)
266 {
267  if (_data.empty()) {
268  return;
269  }
270 
271  SdfListOp<value_type> valueListOp;
272  valueListOp.SetItems(_data, _op);
273  valueListOp.ModifyOperations(
274  [this, &cb](const value_type &t) {
275  return _ModifyCallbackHelper(cb, _GetTypePolicy(), t);
276  });
277 
278  _UpdateFieldData(valueListOp.GetItems(_op));
279 }
280 
281 template <class TP, class FST>
282 void
283 Sdf_VectorListEditor<TP, FST>::ApplyEditsToList(
284  value_vector_type* vec, const ApplyCallback& cb)
285 {
286  if (_data.empty()) {
287  return;
288  }
289 
290  SdfListOp<value_type> valueListOp;
291  valueListOp.SetItems(_data, _op);
292  valueListOp.ApplyOperations(vec, cb);
293 }
294 
295 template <class TP, class FST>
296 bool
297 Sdf_VectorListEditor<TP, FST>::ReplaceEdits(
298  SdfListOpType op, size_t index, size_t n, const value_vector_type& elems)
299 {
300  if (op != _op) {
301  return false;
302  }
303 
304  SdfListOp<value_type> fieldListOp;
305  fieldListOp.SetItems(_data, op);
306  if (!fieldListOp.ReplaceOperations(
307  op, index, n, _GetTypePolicy().Canonicalize(elems))) {
308  return false;
309  }
310 
311  _UpdateFieldData(fieldListOp.GetItems(op));
312  return true;
313 }
314 
315 template <class TP, class FST>
316 void
317 Sdf_VectorListEditor<TP, FST>::ApplyList(
318  SdfListOpType op, const Sdf_ListEditor<TP>& rhs)
319 {
320  const This* rhsEdit = dynamic_cast<const This*>(&rhs);
321  if (!rhsEdit) {
322  TF_CODING_ERROR("Cannot apply from list editor of different type");
323  return;
324  }
325 
326  if (op != _op && op != rhsEdit->_op) {
327  return;
328  }
329 
331  self.SetItems(_data, op);
332 
333  SdfListOp<value_type> stronger;
334  stronger.SetItems(rhsEdit->_data, op);
335 
336  self.ComposeOperations(stronger, op);
337 
338  _UpdateFieldData(self.GetItems(op));
339 }
340 
341 template <class TP, class FST>
342 const typename Sdf_VectorListEditor<TP, FST>::value_vector_type&
343 Sdf_VectorListEditor<TP, FST>::_GetOperations(SdfListOpType op) const
344 {
345  if (op != _op) {
346  static const value_vector_type empty;
347  return empty;
348  }
349 
350  return _data;
351 }
352 
353 PXR_NAMESPACE_CLOSE_SCOPE
354 
355 #endif // SDF_VECTOR_LIST_EDITOR_H
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
Definition: diagnostic.h:87
SDF_API void SetItems(const ItemVector &items, SdfListOpType type)
Sets the item vector for the given operation type.
TF_API std::vector< TfToken > TfToTokenVector(const std::vector< std::string > &sv)
Convert the vector of strings sv into a vector of TfToken.
SDF_API bool ModifyOperations(const ModifyCallback &callback)
Modifies operations specified in this object.
Token for efficient comparison, assignment, and hashing of known strings.
Definition: token.h:89
DANGER DANGER DANGER
Definition: changeBlock.h:72
SDF_API const ItemVector & GetItems(SdfListOpType type) const
Return the item vector identified by type.
Value type representing a list-edit operation.
Definition: listOp.h:75
SDF_API bool ReplaceOperations(const SdfListOpType op, size_t index, size_t n, const ItemVector &newItems)
Replaces the items in the specified operation vector in the range (index, index + n] with the given n...
TF_API std::vector< std::string > TfToStringVector(const std::vector< TfToken > &tv)
Convert the vector of TfToken tv into a vector of strings.
SDF_API void ApplyOperations(ItemVector *vec, const ApplyCallback &cb=ApplyCallback()) const
Applies edit operations to the given ItemVector.