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