vtkSMVectorPropertyTemplate.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (c) Kitware Inc.
2 // SPDX-License-Identifier: BSD-3-Clause
9 #ifndef vtkSMVectorPropertyTemplate_h
10 #define vtkSMVectorPropertyTemplate_h
11 
12 #include "vtkCommand.h" // for vtkCommand enums
13 #include "vtkPVXMLElement.h" // for vtkPVXMLElement
14 
15 // clang-format off
16 #include "vtk_doubleconversion.h" // for double conversion
17 #include VTK_DOUBLECONVERSION_HEADER(double-conversion.h)
18 // clang-format on
19 
20 #include <algorithm> // for std::equal
21 #include <cassert> // for assert
22 #include <sstream> // for std::ostringstream
23 #include <string> // for std::string
24 #include <vector> // for std::vector
25 
26 class vtkSMProperty;
27 
28 namespace
29 {
30 
31 template <typename T>
32 std::string AsString(const T& var)
33 {
34  std::ostringstream str;
35  str << var;
36  return str.str();
37 }
38 
39 template <>
40 vtkMaybeUnused("not used in non-double specializations") inline std::string
41  AsString(const double& var)
42 {
43  char buf[256];
44  const double_conversion::DoubleToStringConverter& converter =
45  double_conversion::DoubleToStringConverter::EcmaScriptConverter();
46  double_conversion::StringBuilder builder(buf, sizeof(buf));
47  builder.Reset();
48  converter.ToShortest(var, &builder);
49  return builder.Finalize();
50 }
51 
52 template <class B>
53 B vtkSMVPConvertFromString(const std::string& string_representation)
54 {
55  B value = B();
56  std::istringstream buffer(string_representation);
57  buffer >> value;
58  return value;
59 }
60 
61 template <>
62 vtkMaybeUnused("not used in non-string specializations") inline std::string
63  vtkSMVPConvertFromString<std::string>(const std::string& string_representation)
64 {
65  return string_representation;
66 }
67 }
68 
69 template <class T>
71 {
72  vtkSMProperty* Property;
73 
74 public:
75  std::vector<T> Values;
76  std::vector<T> UncheckedValues;
77  std::vector<T> DefaultValues; // Values set in the XML configuration.
80 
81  //---------------------------------------------------------------------------
83  {
84  this->Property = property;
85  this->DefaultsValid = false;
86  this->Initialized = false;
87  }
88 
89  //---------------------------------------------------------------------------
91  {
92  this->DefaultValues.clear();
93  this->DefaultValues.insert(this->DefaultValues.end(), this->Values.begin(), this->Values.end());
94  this->DefaultsValid = true;
95  }
96 
97  //---------------------------------------------------------------------------
98  void SetNumberOfUncheckedElements(unsigned int num)
99  {
100  this->UncheckedValues.resize(num);
101  this->Property->InvokeEvent(vtkCommand::UncheckedPropertyModifiedEvent);
102  }
103 
104  //---------------------------------------------------------------------------
106  {
107  return static_cast<unsigned int>(this->UncheckedValues.size());
108  }
109 
110  //---------------------------------------------------------------------------
111  unsigned int GetNumberOfElements() { return static_cast<unsigned int>(this->Values.size()); }
112 
113  //---------------------------------------------------------------------------
114  void SetNumberOfElements(unsigned int num)
115  {
116  if (num == this->Values.size())
117  {
118  return;
119  }
120  this->Values.resize(num);
121  this->UncheckedValues.resize(num);
122  if (num == 0)
123  {
124  // If num == 0, then we already have the initialized values (so to speak).
125  this->Initialized = true;
126  }
127  else
128  {
129  this->Initialized = false;
130  }
131  this->Property->Modified();
132  }
133 
134  //---------------------------------------------------------------------------
135  T& GetElement(unsigned int idx)
136  {
137  assert(idx < this->Values.size());
138  return this->Values[idx];
139  }
140 
141  //---------------------------------------------------------------------------
142  // seems weird that this idx is "int".
143  T& GetDefaultValue(int idx)
144  {
145  if (idx >= 0 && idx < static_cast<int>(this->DefaultValues.size()))
146  {
147  return this->DefaultValues[idx];
148  }
149 
150  static T empty_value = T();
151  return empty_value;
152  }
153 
154  //---------------------------------------------------------------------------
155  T* GetElements() { return !this->Values.empty() ? &this->Values[0] : nullptr; }
156 
157  //---------------------------------------------------------------------------
159  {
160  return (!this->UncheckedValues.empty()) ? &this->UncheckedValues[0] : nullptr;
161  }
162  //---------------------------------------------------------------------------
163  T& GetUncheckedElement(unsigned int idx)
164  {
165  assert(idx < this->UncheckedValues.size());
166  return this->UncheckedValues[idx];
167  }
168 
169  //---------------------------------------------------------------------------
170  void SetUncheckedElement(unsigned int idx, T value)
171  {
172  if (idx >= this->GetNumberOfUncheckedElements())
173  {
174  this->UncheckedValues.resize(idx + 1);
175  }
176 
177  if (this->UncheckedValues[idx] != value)
178  {
179  this->UncheckedValues[idx] = value;
180  this->Property->InvokeEvent(vtkCommand::UncheckedPropertyModifiedEvent);
181  }
182  }
183 
184  //---------------------------------------------------------------------------
185  int SetUncheckedElements(const T* values)
186  {
187  return this->SetUncheckedElements(values, this->GetNumberOfUncheckedElements());
188  }
189 
190  //---------------------------------------------------------------------------
191  int SetUncheckedElements(const T* values, unsigned int numValues)
192  {
193  bool modified = false;
194  unsigned int numArgs = this->GetNumberOfUncheckedElements();
195  if (numArgs != numValues)
196  {
197  this->UncheckedValues.resize(numValues);
198  numArgs = numValues;
199  modified = true;
200  }
201  else
202  {
203  modified = !std::equal(this->UncheckedValues.begin(), this->UncheckedValues.end(), values);
204  }
205 
206  if (!modified)
207  {
208  return 1;
209  }
210 
211  std::copy(values, values + numArgs, this->UncheckedValues.begin());
212 
213  this->Property->InvokeEvent(vtkCommand::UncheckedPropertyModifiedEvent);
214  return 1;
215  }
216 
217  //---------------------------------------------------------------------------
218  int SetElement(unsigned int idx, T value)
219  {
220  unsigned int numElems = this->GetNumberOfElements();
221 
222  if (this->Initialized && idx < numElems && value == this->GetElement(idx))
223  {
224  return 1;
225  }
226 
227  if (idx >= numElems)
228  {
229  this->SetNumberOfElements(idx + 1);
230  }
231  this->Values[idx] = value;
232 
233  // Make sure to initialize BEFORE Modified() is called. Otherwise,
234  // the value would not be pushed.
235  this->Initialized = true;
236  this->Property->Modified();
237  this->ClearUncheckedElements();
238  return 1;
239  }
240 
241  //---------------------------------------------------------------------------
242  int SetElements(const T* values)
243  {
244  return this->SetElements(values, this->GetNumberOfElements());
245  }
246 
247  //---------------------------------------------------------------------------
248  int SetElements(const T* values, unsigned int numValues)
249  {
250  bool modified = false;
251  unsigned int numArgs = this->GetNumberOfElements();
252  if (numArgs != numValues)
253  {
254  this->Values.resize(numValues);
255  this->UncheckedValues.resize(numValues);
256  numArgs = numValues;
257  modified = true;
258  }
259  else
260  {
261  modified = !std::equal(this->Values.begin(), this->Values.end(), values);
262  }
263  if (!modified && this->Initialized)
264  {
265  return 1;
266  }
267 
268  std::copy(values, values + numArgs, this->Values.begin());
269  this->Initialized = true;
270  if (!modified && numValues == 0)
271  {
272  // handle the case when the property didn't have valid values but the new
273  // values don't really change anything. In that case, the property hasn't
274  // really been modified, so skip invoking the event. This keeps Python
275  // trace from ending up with lots of properties such as EdgeBlocks etc for
276  // ExodusIIReader which haven't really changed at all.
277  }
278  else
279  {
280  this->Property->Modified();
281  this->ClearUncheckedElements();
282  }
283  return 1;
284  }
285 
286  //---------------------------------------------------------------------------
287  int AppendUncheckedElements(const T* values, unsigned int numValues)
288  {
289  this->UncheckedValues.insert(std::end(this->UncheckedValues), values, values + numValues);
290  this->Property->InvokeEvent(vtkCommand::UncheckedPropertyModifiedEvent);
291 
292  return 1;
293  }
294 
295  //---------------------------------------------------------------------------
296  int AppendElements(const T* values, unsigned int numValues)
297  {
298  this->Values.insert(std::end(this->Values), values, values + numValues);
299  this->Initialized = true;
300  this->Property->Modified();
301  this->ClearUncheckedElements();
302 
303  return 1;
304  }
305 
306  //---------------------------------------------------------------------------
308  {
309  if (dsrc && dsrc->Initialized)
310  {
311  bool modified = false;
312 
313  if (this->Values != dsrc->Values)
314  {
315  this->Values = dsrc->Values;
316  modified = true;
317  }
318  // If we were not initialized, we are now modified even if the value
319  // did not change
320  modified = modified || !this->Initialized;
321  this->Initialized = true;
322 
323  if (modified)
324  {
325  this->Property->Modified();
326  }
327 
328  // now copy unchecked values.
329  if (this->UncheckedValues != dsrc->Values)
330  {
331  this->UncheckedValues = dsrc->Values;
332  modified = true;
333  }
334  if (modified)
335  {
336  this->Property->InvokeEvent(vtkCommand::UncheckedPropertyModifiedEvent);
337  }
338  }
339  }
340 
341  //---------------------------------------------------------------------------
343  {
344  if (this->DefaultsValid)
345  {
346  if (this->DefaultValues != this->Values || this->DefaultValues != this->UncheckedValues)
347  {
348  this->Values = this->DefaultValues;
349  // Make sure to initialize BEFORE Modified() is called. Otherwise,
350  // the value would not be pushed.
351  this->Initialized = true;
352  this->Property->Modified();
353  this->ClearUncheckedElements();
354  }
355  }
356  else if (this->Property->GetRepeatable())
357  {
358  this->Values.clear();
359  this->Initialized = true;
360  this->Property->Modified();
361  this->ClearUncheckedElements();
362  }
363  }
364 
365  //---------------------------------------------------------------------------
367  {
368  if (!element)
369  {
370  return false;
371  }
372 
373  std::vector<T> new_values;
374  unsigned int numElems = element->GetNumberOfNestedElements();
375  for (unsigned int i = 0; i < numElems; i++)
376  {
377  vtkPVXMLElement* current = element->GetNestedElement(i);
378  if (current->GetName() && strcmp(current->GetName(), "Element") == 0)
379  {
380  int index;
381  const char* str_value = current->GetAttribute("value");
382  if (str_value && current->GetScalarAttribute("index", &index) && index >= 0)
383  {
384  if (index <= static_cast<int>(new_values.size()))
385  {
386  new_values.resize(index + 1);
387  }
388 
389  new_values[index] = vtkSMVPConvertFromString<T>(str_value);
390  }
391  }
392  }
393  if (!new_values.empty())
394  {
395  this->SetElements(&new_values[0], static_cast<unsigned int>(new_values.size()));
396  }
397  else
398  {
399  this->SetNumberOfElements(0);
400  }
401 
402  return true;
403  }
404 
405  //---------------------------------------------------------------------------
406  void SaveStateValues(vtkPVXMLElement* propertyElement)
407  {
408  unsigned int size = this->GetNumberOfElements();
409  if (size > 0)
410  {
411  propertyElement->AddAttribute("number_of_elements", size);
412  }
413 
414  // helps save full precision doubles and floats.
415  for (unsigned int i = 0; i < size; i++)
416  {
417  vtkPVXMLElement* elementElement = vtkPVXMLElement::New();
418  elementElement->SetName("Element");
419  elementElement->AddAttribute("index", i);
420  elementElement->AddAttribute("value", ::AsString(this->GetElement(i)).c_str());
421  propertyElement->AddNestedElement(elementElement);
422  elementElement->Delete();
423  }
424  }
425 
426  //---------------------------------------------------------------------------
428  {
429  // copy values to unchecked values
430  this->UncheckedValues = this->Values;
431  this->Property->InvokeEvent(vtkCommand::UncheckedPropertyModifiedEvent);
432  }
433 
434  //---------------------------------------------------------------------------
436  {
437  if (this->Values.size() != this->DefaultValues.size())
438  {
439  return false;
440  }
441 
442  return std::equal(this->Values.begin(), this->Values.end(), this->DefaultValues.begin());
443  }
444 };
445 #endif
446 
447 // VTK-HeaderTest-Exclude: vtkSMVectorPropertyTemplate.h
unsigned int GetNumberOfNestedElements()
Get the number of elements nested in this one.
void AddAttribute(const char *attrName, const char *attrValue)
Given it&#39;s name and value, add an attribute.
void Copy(vtkSMVectorPropertyTemplate< T > *dsrc)
void SetNumberOfElements(unsigned int num)
int GetScalarAttribute(const char *name, int *value)
Get the attribute with the given name converted to a scalar value.
int SetUncheckedElements(const T *values, unsigned int numValues)
static vtkPVXMLElement * New()
int InvokeEvent(unsigned long event)
int SetElement(unsigned int idx, T value)
void SetUncheckedElement(unsigned int idx, T value)
superclass for all SM properties
void SetNumberOfUncheckedElements(unsigned int num)
void Modified() override
Overridden to support blocking of modified events.
virtual int GetRepeatable()
If repeatable, a property can have 1 or more values of the same kind.
const char * GetAttribute(const char *name)
Get the attribute with the given name.
vtkPVXMLElement * GetNestedElement(unsigned int index)
Get the element nested in this one at the given index.
void SaveStateValues(vtkPVXMLElement *propertyElement)
int SetElements(const T *values, unsigned int numValues)
vtkSMVectorPropertyTemplate(vtkSMProperty *property)
size
int AppendElements(const T *values, unsigned int numValues)
int AppendUncheckedElements(const T *values, unsigned int numValues)
bool LoadStateValues(vtkPVXMLElement *element)
value
virtual char * GetName()
Set/Get the name of the element.
void AddNestedElement(vtkPVXMLElement *element, int setPrent)
Add a sub-element.
This is used by vtkPVXMLParser to represent an XML document starting at the root element.
#define const
Definition: zconf.h:238
index
virtual void SetName(const char *)
Set/Get the name of the element.
virtual void Delete()