Mantid
Loading...
Searching...
No Matches
PropertyWithValue.hxx
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
8
10#include "MantidKernel/Logger.h"
16
17#ifndef Q_MOC_RUN
18#include <boost/algorithm/string/trim.hpp>
19#include <memory>
20#endif
21
24#include "MantidNexus/NexusFile.h"
25#include <json/value.h>
26#include <type_traits>
27#include <vector>
28
29namespace Mantid {
30namespace Kernel {
31
32//------------------------------------------------------------------------------------------------
33// Now the PropertyWithValue class itself
34//------------------------------------------------------------------------------------------------
35
43template <typename TYPE>
45 unsigned int direction)
46 : Property(std::move(name), typeid(TYPE), direction), m_value(defaultValue),
47 m_initialValue(std::move(defaultValue)),
48 m_validator(validator ? std::move(validator) : std::make_shared<NullValidator>()) {}
56template <typename TYPE>
57PropertyWithValue<TYPE>::PropertyWithValue(std::string name, TYPE defaultValue, unsigned int direction)
58 : Property(std::move(name), typeid(TYPE), direction), m_value(defaultValue),
59 m_initialValue(std::move(defaultValue)), m_validator(std::make_shared<NullValidator>()) {}
61/*
62 Constructor to handle vector value assignments to m_initialValue
63 so they can be remembered when the algorithm dialog is reloaded.
64*/
75template <typename TYPE>
76PropertyWithValue<TYPE>::PropertyWithValue(const std::string &name, const TYPE &defaultValue,
77 const std::string &defaultValueStr, IValidator_sptr validator,
78 unsigned int direction)
79 : Property(name, typeid(TYPE), direction), m_value(extractToValueVector<TYPE>(defaultValueStr)),
80 m_initialValue(m_value), m_validator(validator ? std::move(validator) : std::make_shared<NullValidator>()) {
81 UNUSED_ARG(defaultValue);
82}
88template <typename TYPE>
90 : Property(right), m_value(right.m_value), m_initialValue(right.m_initialValue), // the default is the initial
91 // value of the original object
92 m_validator(right.m_validator->clone()) {}
93
96 return new PropertyWithValue<TYPE>(*this);
97}
98
99template <typename TYPE> void PropertyWithValue<TYPE>::saveProperty(Nexus::File *file) {
100 if constexpr (std::is_same_v<TYPE, float> || std::is_same_v<TYPE, double> || std::is_same_v<TYPE, int32_t> ||
101 std::is_same_v<TYPE, uint32_t> || std::is_same_v<TYPE, int64_t> || std::is_same_v<TYPE, uint64_t> ||
102 std::is_same_v<TYPE, long> || std::is_same_v<TYPE, std::string> ||
103 std::is_same_v<TYPE, std::vector<double>> || std::is_same_v<TYPE, std::vector<int32_t>>) {
104 file->makeGroup(this->name(), "NXlog", true);
105 file->writeData("value", m_value);
106 file->openData("value");
107 file->putAttr("units", this->units());
108 file->closeData();
109 file->closeGroup();
110 } else {
111 // AppleClang 7.3 and later gives a -Winfinite-recursion warning if I call the
112 // base class method. The function is small enough that reimplementing it
113 // isn't a big deal.
114 throw std::invalid_argument("PropertyWithValue::saveProperty - Cannot save '" + this->name() + "', property type " +
115 typeid(TYPE).name() + " not implemented.");
116 }
117}
118
122template <typename TYPE> std::string PropertyWithValue<TYPE>::value() const { return toString(m_value); }
123
127template <typename TYPE>
128std::string PropertyWithValue<TYPE>::valueAsPrettyStr(const size_t maxLength, const bool collapseLists) const {
129 std::string retVal;
130 try {
131 retVal = toPrettyString(m_value, maxLength, collapseLists);
132 } catch (boost::bad_lexical_cast &) {
133 // toPrettyStringFailed, default to using toString instead
134 retVal = Strings::shorten(value(), maxLength);
135 }
136 return retVal;
137}
138
143template <typename TYPE> Json::Value PropertyWithValue<TYPE>::valueAsJson() const { return encodeAsJson((*this)()); }
144
150template <typename TYPE> bool PropertyWithValue<TYPE>::operator==(const PropertyWithValue<TYPE> &rhs) const {
151 if (this->name() != rhs.name())
152 return false;
153 return (m_value == rhs.m_value);
154}
155
161template <typename TYPE> bool PropertyWithValue<TYPE>::operator!=(const PropertyWithValue<TYPE> &rhs) const {
162 return !(*this == rhs);
163}
164
167template <typename TYPE> int PropertyWithValue<TYPE>::size() const { return findSize(m_value); }
168
172template <typename TYPE> std::string PropertyWithValue<TYPE>::getDefault() const { return toString(m_initialValue); }
173
181template <typename TYPE> std::string PropertyWithValue<TYPE>::setValue(const std::string &value) {
182 try {
183 TYPE result = m_value;
184 std::string valueCopy = value;
185 if (autoTrim()) {
186 boost::trim(valueCopy);
187 }
188 toValue(valueCopy, result);
189 // Uses the assignment operator defined below which runs isValid() and
190 // throws based on the result
191 *this = result;
192 return "";
193 } catch (boost::bad_lexical_cast &) {
194 std::string error = "Could not set property " + name() + ". Can not convert \"" + value + "\" to " + type();
195 g_logger.debug() << error;
196 return error;
197 } catch (std::invalid_argument &except) {
198 g_logger.debug() << "Could not set property " << name() << ": " << except.what();
199 return except.what();
200 }
201}
202
209template <typename TYPE> std::string PropertyWithValue<TYPE>::setValueFromJson(const Json::Value &value) {
210 if (value.type() != Json::stringValue) {
211 try {
212 *this = decode<TYPE>(value);
213 } catch (std::invalid_argument &exc) {
214 return exc.what();
215 }
216 return "";
217 } else {
218 return setValue(value.asString());
219 }
220}
221
228template <typename TYPE> std::string PropertyWithValue<TYPE>::setDataItem(const std::shared_ptr<DataItem> &data) {
229 // Pass of the helper function that is able to distinguish whether
230 // the TYPE of the PropertyWithValue can be converted to a
231 // shared_ptr<DataItem>
232 return setTypedValue(data, std::is_convertible<TYPE, std::shared_ptr<DataItem>>());
233}
234
237// cppcheck-suppress operatorEqVarError
239 if (&right == this)
240 return *this;
242 m_validator = right.m_validator->clone();
243 return *this;
244}
245
246//--------------------------------------------------------------------------------------
252 PropertyWithValue const *rhs = dynamic_cast<PropertyWithValue const *>(right);
253
254 if (rhs) {
255 // This function basically does:
256 // m_value += rhs->m_value; for values
257 // or concatenates vectors for vectors
258 addingOperator(m_value, rhs->m_value);
259 } else
260 g_logger.warning() << "PropertyWithValue " << this->name()
261 << " could not be added to another property of the "
262 "same name but incompatible type.\n";
263
264 return *this;
265}
266
267//--------------------------------------------------------------------------------------
275 TYPE oldValue = m_value;
276 if constexpr (std::is_same<TYPE, std::string>::value) {
277 std::string valueCopy = toString(value);
278 if (autoTrim()) {
279 boost::trim(valueCopy);
280 }
281 toValue(valueCopy, m_value);
282 } else {
283 m_value = value;
284 }
285 std::string problem = this->isValid();
286 if (problem.empty()) {
287 return *this;
288 } else if (problem == "_alias") {
289 m_value = getValueForAlias(value);
290 return *this;
291 } else {
292 m_value = oldValue;
293 throw std::invalid_argument("When setting value of property \"" + this->name() + "\": " + problem);
294 }
295}
296
301template <typename TYPE> const TYPE &PropertyWithValue<TYPE>::operator()() const { return m_value; }
302
307template <typename TYPE> PropertyWithValue<TYPE>::operator const TYPE &() const { return m_value; }
308
316template <typename TYPE> std::string PropertyWithValue<TYPE>::isValid() const { return m_validator->isValid(m_value); }
317
324template <typename TYPE> bool PropertyWithValue<TYPE>::isDefault() const { return m_initialValue == m_value; }
325
331template <typename TYPE> std::vector<std::string> PropertyWithValue<TYPE>::allowedValues() const {
333}
334
341 return m_validator->isMultipleSelectionAllowed();
342}
343
348template <typename TYPE> void PropertyWithValue<TYPE>::replaceValidator(IValidator_sptr newValidator) {
349 m_validator = newValidator;
350}
351
359template <typename TYPE> std::string PropertyWithValue<TYPE>::setValueFromProperty(const Property &right) {
360
361 if (auto prop = dynamic_cast<const PropertyWithValue<TYPE> *>(&right)) {
362 m_value = prop->m_value;
363 return "";
364 } else {
365 return setValue(right.value());
366 }
367}
368
376template <typename TYPE>
377template <typename U>
378std::string PropertyWithValue<TYPE>::setTypedValue(const U &value, const std::true_type &) {
379 TYPE data = std::dynamic_pointer_cast<typename TYPE::element_type>(value);
380 std::string msg;
381 if (data) {
382 try {
383 (*this) = data;
384 } catch (std::invalid_argument &exc) {
385 msg = exc.what();
386 }
387 } else {
388 msg = "Invalid DataItem. The object type (" + std::string(typeid(value).name()) +
389 ") does not match the declared type of the property (" + std::string(this->type()) + ").";
390 }
391 return msg;
392}
393
401template <typename TYPE>
402template <typename U>
403std::string PropertyWithValue<TYPE>::setTypedValue(const U &value, const std::false_type &) {
405 return "Attempt to assign object of type DataItem to property (" + name() + ") of incorrect type";
406}
407
413template <typename TYPE> const TYPE PropertyWithValue<TYPE>::getValueForAlias(const TYPE &alias) const {
414 std::string strAlias = toString(alias);
415 std::string strValue = m_validator->getValueForAlias(strAlias);
416 TYPE typeValue;
417 toValue(strValue, typeValue);
418 return typeValue;
419}
420
425template <typename TYPE> IValidator_sptr PropertyWithValue<TYPE>::getValidator() const { return m_validator; }
426
427} // namespace Kernel
428} // namespace Mantid
const std::string & m_value
Definition Algorithm.cpp:72
Kernel::IValidator_sptr m_validator
std::string name
Definition Run.cpp:60
const std::vector< double > & rhs
double value
The value of the point.
Definition FitMW.cpp:51
double error
double right
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition System.h:44
NullValidator is a validator that doesn't.
The concrete, templated class for properties.
virtual void replaceValidator(IValidator_sptr newValidator)
Replace the current validator with the given one.
bool isDefault() const override
Indicates if the property's value is the same as it was when it was set N.B.
int size() const override
Get the size of the property.
PropertyWithValue & operator=(const PropertyWithValue &right)
Copy assignment operator assigns only the value and the validator not the name, default (initial) val...
std::string setTypedValue(const U &value, const std::true_type &)
Helper function for setValue(DataItem_sptr).
std::string setValue(const std::string &value) override
Set the value of the property from a string representation.
PropertyWithValue & operator+=(Property const *right) override
Add the value of another property.
std::string valueAsPrettyStr(const size_t maxLength=0, const bool collapseLists=true) const override
Get the value of the property as a string.
Json::Value valueAsJson() const override
Attempt to construct a Json::Value object from the plain value.
bool operator==(const PropertyWithValue< TYPE > &rhs) const
Deep comparison.
bool isMultipleSelectionAllowed() override
Returns the set of valid values for this property, if such a set exists.
void saveProperty(Nexus::File *file) override
PropertyWithValue< TYPE > * clone() const override
'Virtual copy constructor'
const TYPE getValueForAlias(const TYPE &alias) const
Return value for a given alias.
virtual const TYPE & operator()() const
Allows you to get the value of the property via an expression like myProperty()
std::string setValueFromJson(const Json::Value &value) override
Set the value of the property from a Json representation.
IValidator_sptr getValidator() const
Returns the validator as a constant variable so it cannot be changed.
std::vector< std::string > allowedValues() const override
Returns the set of valid values for this property, if such a set exists.
TYPE m_value
The value of the property.
std::string value() const override
Get the value of the property as a string.
std::string isValid() const override
Check the value chosen for the property is OK, unless overidden it just calls the validator's isValid...
bool operator!=(const PropertyWithValue< TYPE > &rhs) const
Deep comparison (not equal).
std::string setValueFromProperty(const Property &right) override
Set the value of the property via a reference to another property.
std::string setDataItem(const std::shared_ptr< DataItem > &data) override
Set a property value via a DataItem.
std::string getDefault() const override
Get the value the property was initialised with -its default value.
Base class for properties.
Definition Property.h:95
const std::string & name() const
Get the property's name.
Definition Property.cpp:63
MANTID_KERNEL_DLL std::string shorten(const std::string &input, const size_t max_length)
Converts long strings into "start ... end".
Definition Strings.cpp:53
T extractToValueVector(const std::string &strvalue)
void toValue(const std::string &strvalue, T &value)
std::string toString(const T &value)
Convert values to strings.
std::vector< std::string > determineAllowedValues(const T &, const IValidator &validator)
void addingOperator(T &lhs, const T &rhs)
int findSize(const T &)
Specialization for any type, should be appropriate for properties with a single value.
MANTID_KERNEL_DLL::Json::Value encodeAsJson(const OptionalBool &)
Encode an OptionalBool as a Json::Value.
std::shared_ptr< IValidator > IValidator_sptr
A shared_ptr to an IValidator.
std::string toPrettyString(const T &value, size_t maxLength=0, bool collapseLists=true)
Convert values to pretty strings.
Helper class which provides the Collimation Length for SANS instruments.
STL namespace.